From 5d1320928c57642853f47108169e8ec663e56d5d Mon Sep 17 00:00:00 2001 From: Ammar ELWazir Date: Wed, 8 May 2024 01:47:31 -0500 Subject: [PATCH] SWDEV-419012: Adding New Perfetto SDK & Fixing early destruction of perfetto plugin Change-Id: Ie1d8e753f10a1ba0686b021c14b788b444499f14 --- .gitmodules | 6 + cmake_modules/rocprofiler_utils.cmake | 149 + plugin/perfetto/CMakeLists.txt | 16 +- plugin/perfetto/perfetto | 1 + plugin/perfetto/perfetto.cpp | 98 +- plugin/perfetto/perfetto_sdk/CMakeLists.txt | 8 - plugin/perfetto/perfetto_sdk/LICENSE | 189 - plugin/perfetto/perfetto_sdk/OWNERS | 35 - .../perfetto/perfetto_sdk/docs/tracing-sdk.md | 394 - plugin/perfetto/perfetto_sdk/sdk/perfetto.cc | 80065 --------- plugin/perfetto/perfetto_sdk/sdk/perfetto.h | 139056 --------------- src/tools/tool.cpp | 9 +- 12 files changed, 218 insertions(+), 219808 deletions(-) create mode 100644 .gitmodules create mode 160000 plugin/perfetto/perfetto delete mode 100644 plugin/perfetto/perfetto_sdk/CMakeLists.txt delete mode 100644 plugin/perfetto/perfetto_sdk/LICENSE delete mode 100644 plugin/perfetto/perfetto_sdk/OWNERS delete mode 100644 plugin/perfetto/perfetto_sdk/docs/tracing-sdk.md delete mode 100644 plugin/perfetto/perfetto_sdk/sdk/perfetto.cc delete mode 100644 plugin/perfetto/perfetto_sdk/sdk/perfetto.h diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..2328b58479 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ + + +[submodule "perfetto"] + path = plugin/perfetto/perfetto + url = https://github.com/google/perfetto.git + branch = releases/v44.x diff --git a/cmake_modules/rocprofiler_utils.cmake b/cmake_modules/rocprofiler_utils.cmake index 9b0607f44a..ad4134eb2d 100644 --- a/cmake_modules/rocprofiler_utils.cmake +++ b/cmake_modules/rocprofiler_utils.cmake @@ -112,3 +112,152 @@ function(rocprofiler_get_version DEFAULT_VERSION_STRING) PARENT_SCOPE) endfunction() + +# ----------------------------------------------------------------------------------------# +# macro rocprofiler_checkout_git_submodule() +# +# Run "git submodule update" if a file in a submodule does not exist +# +# ARGS: RECURSIVE (option) -- add "--recursive" flag RELATIVE_PATH (one value) -- +# typically the relative path to submodule from PROJECT_SOURCE_DIR WORKING_DIRECTORY (one +# value) -- (default: PROJECT_SOURCE_DIR) TEST_FILE (one value) -- file to check for +# (default: CMakeLists.txt) ADDITIONAL_CMDS (many value) -- any addition commands to pass +# +function(ROCPROFILER_CHECKOUT_GIT_SUBMODULE) + # parse args + cmake_parse_arguments( + CHECKOUT "RECURSIVE" + "RELATIVE_PATH;WORKING_DIRECTORY;TEST_FILE;REPO_URL;REPO_BRANCH" + "ADDITIONAL_CMDS" ${ARGN}) + + if(NOT CHECKOUT_WORKING_DIRECTORY) + set(CHECKOUT_WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + endif() + + if(NOT CHECKOUT_TEST_FILE) + set(CHECKOUT_TEST_FILE "CMakeLists.txt") + endif() + + find_package(Git) + set(_DIR "${CHECKOUT_WORKING_DIRECTORY}/${CHECKOUT_RELATIVE_PATH}") + # ensure the (possibly empty) directory exists + if(NOT EXISTS "${_DIR}") + if(NOT CHECKOUT_REPO_URL) + message(FATAL_ERROR "submodule directory does not exist") + endif() + endif() + + # if this file exists --> project has been checked out if not exists --> not been + # checked out + set(_TEST_FILE "${_DIR}/${CHECKOUT_TEST_FILE}") + # assuming a .gitmodules file exists + set(_SUBMODULE "${PROJECT_SOURCE_DIR}/.gitmodules") + + set(_TEST_FILE_EXISTS OFF) + if(EXISTS "${_TEST_FILE}" AND NOT IS_DIRECTORY "${_TEST_FILE}") + set(_TEST_FILE_EXISTS ON) + endif() + + if(_TEST_FILE_EXISTS) + return() + endif() + + find_package(Git REQUIRED) + + set(_SUBMODULE_EXISTS OFF) + if(EXISTS "${_SUBMODULE}" AND NOT IS_DIRECTORY "${_SUBMODULE}") + set(_SUBMODULE_EXISTS ON) + endif() + + set(_HAS_REPO_URL OFF) + if(NOT "${CHECKOUT_REPO_URL}" STREQUAL "") + set(_HAS_REPO_URL ON) + endif() + + # if the module has not been checked out + if(NOT _TEST_FILE_EXISTS AND _SUBMODULE_EXISTS) + # perform the checkout + execute_process( + COMMAND ${GIT_EXECUTABLE} submodule update --init ${_RECURSE} + ${CHECKOUT_ADDITIONAL_CMDS} ${CHECKOUT_RELATIVE_PATH} + WORKING_DIRECTORY ${CHECKOUT_WORKING_DIRECTORY} + RESULT_VARIABLE RET) + + # check the return code + if(RET GREATER 0) + set(_CMD "${GIT_EXECUTABLE} submodule update --init ${_RECURSE} + ${CHECKOUT_ADDITIONAL_CMDS} ${CHECKOUT_RELATIVE_PATH}") + message(STATUS "function(rocprofiler_checkout_git_submodule) failed.") + message(FATAL_ERROR "Command: \"${_CMD}\"") + else() + set(_TEST_FILE_EXISTS ON) + endif() + endif() + + if(NOT _TEST_FILE_EXISTS AND _HAS_REPO_URL) + message( + STATUS + "Cloning '${CHECKOUT_REPO_URL}' into ${CHECKOUT_WORKING_DIRECTORY}/${CHECKOUT_RELATIVE_PATH}..." + ) + + # remove the existing directory + if(EXISTS "${_DIR}") + execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory ${_DIR}) + endif() + + # perform the checkout + execute_process( + COMMAND ${GIT_EXECUTABLE} clone ${CHECKOUT_ADDITIONAL_CMDS} + ${CHECKOUT_REPO_URL} ${CHECKOUT_RELATIVE_PATH} + WORKING_DIRECTORY ${CHECKOUT_WORKING_DIRECTORY} + RESULT_VARIABLE RET_CLONE) + + if(NOT RET_CLONE EQUAL 0) + message( + SEND_ERROR + "Failed to clone ${CHECKOUT_REPO_URL} into ${CHECKOUT_WORKING_DIRECTORY}/${CHECKOUT_RELATIVE_PATH}" + ) + return() + endif() + + if(CHECKOUT_REPO_BRANCH) + execute_process( + COMMAND ${GIT_EXECUTABLE} checkout ${CHECKOUT_REPO_BRANCH} + WORKING_DIRECTORY ${CHECKOUT_WORKING_DIRECTORY}/${CHECKOUT_RELATIVE_PATH} + RESULT_VARIABLE RET_BRANCH) + + if(NOT RET_BRANCH EQUAL 0) + message( + SEND_ERROR + "Failed to checkout '${CHECKOUT_REPO_BRANCH}' for ${CHECKOUT_REPO_URL} in ${CHECKOUT_WORKING_DIRECTORY}/${CHECKOUT_RELATIVE_PATH}" + ) + return() + endif() + endif() + + # perform the submodule update + if(CHECKOUT_RECURSIVE + AND EXISTS "${_DIR}" + AND IS_DIRECTORY "${_DIR}") + execute_process( + COMMAND ${GIT_EXECUTABLE} submodule update --init ${_RECURSE} + WORKING_DIRECTORY ${_DIR} + RESULT_VARIABLE RET_RECURSIVE) + if(NOT RET_RECURSIVE EQUAL 0) + message( + SEND_ERROR + "Failed to update submodules for ${CHECKOUT_REPO_URL} in ${CHECKOUT_WORKING_DIRECTORY}/${CHECKOUT_RELATIVE_PATH}" + ) + return() + endif() + endif() + + set(_TEST_FILE_EXISTS ON) + endif() + + if(NOT EXISTS "${_TEST_FILE}" OR NOT _TEST_FILE_EXISTS) + message( + FATAL_ERROR + "Error checking out submodule: '${CHECKOUT_RELATIVE_PATH}' to '${_DIR}'") + endif() +endfunction() diff --git a/plugin/perfetto/CMakeLists.txt b/plugin/perfetto/CMakeLists.txt index 9c5ea030c5..f4c7fe240e 100644 --- a/plugin/perfetto/CMakeLists.txt +++ b/plugin/perfetto/CMakeLists.txt @@ -1,8 +1,16 @@ +rocprofiler_checkout_git_submodule( + RECURSIVE + TEST_FILE "sdk" + RELATIVE_PATH perfetto + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + REPO_URL https://github.com/google/perfetto.git + REPO_BRANCH "releases/v44.x") + +include_directories(perfetto/sdk) + file(GLOB ROCPROFILER_UTIL_SRC_FILES ${PROJECT_SOURCE_DIR}/src/utils/helper.cpp) -add_subdirectory(perfetto_sdk) - -add_library(perfetto_plugin ${LIBRARY_TYPE} ${ROCPROFILER_UTIL_SRC_FILES} perfetto.cpp) +add_library(perfetto_plugin ${LIBRARY_TYPE} ${ROCPROFILER_UTIL_SRC_FILES} perfetto/sdk/perfetto.cc perfetto.cpp) set_target_properties( perfetto_plugin @@ -20,7 +28,7 @@ target_link_options( perfetto_plugin PRIVATE -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/../exportmap -Wl,--no-undefined) -target_link_libraries(perfetto_plugin PRIVATE rocprofiler-v2 rocprofiler::perfetto-sdk +target_link_libraries(perfetto_plugin PRIVATE rocprofiler-v2 Threads::Threads stdc++fs amd_comgr) install(TARGETS perfetto_plugin diff --git a/plugin/perfetto/perfetto b/plugin/perfetto/perfetto new file mode 160000 index 0000000000..eb5ef24c58 --- /dev/null +++ b/plugin/perfetto/perfetto @@ -0,0 +1 @@ +Subproject commit eb5ef24c58d13cec289d733d03f0f3f0ed321b12 diff --git a/plugin/perfetto/perfetto.cpp b/plugin/perfetto/perfetto.cpp index e8a1d4c515..b7f4255223 100644 --- a/plugin/perfetto/perfetto.cpp +++ b/plugin/perfetto/perfetto.cpp @@ -45,7 +45,7 @@ #include #include -#include "perfetto_sdk/sdk/perfetto.h" +#include "perfetto/sdk/perfetto.h" #include "rocprofiler_plugin.h" #include "../utils.h" @@ -108,6 +108,7 @@ struct std::hash }; namespace { +std::mutex writing_lock{}; std::string process_name; @@ -156,22 +157,14 @@ class perfetto_plugin_t { perfetto::TrackEvent::Register(); perfetto::protos::gen::TrackEventConfig track_event_cfg; - track_event_cfg.add_disabled_categories("*"); - track_event_cfg.add_enabled_categories("GENERIC"); - track_event_cfg.add_enabled_categories("ROCTX_API"); - track_event_cfg.add_enabled_categories("HSA_API"); - track_event_cfg.add_enabled_categories("HIP_API"); - track_event_cfg.add_enabled_categories("External_API"); - track_event_cfg.add_enabled_categories("HIP_OPS"); - track_event_cfg.add_enabled_categories("HSA_OPS"); - track_event_cfg.add_enabled_categories("MEM_COPIES"); - track_event_cfg.add_enabled_categories("KERNELS"); - track_event_cfg.add_enabled_categories("COUNTERS"); + track_event_cfg.add_enabled_categories("*"); perfetto::TraceConfig trace_cfg; auto buffer_cfg = trace_cfg.add_buffers(); uint32_t max_buffer_size = 1024 * 1024; // Default max buffer size is 1 GB + buffer_cfg->set_fill_policy( + perfetto::protos::gen::TraceConfig_BufferConfig_FillPolicy_RING_BUFFER); const char* max_buffer_size_str = getenv("rocprofiler_PERFETTO_MAX_BUFFER_SIZE_KIB"); if (max_buffer_size_str && std::atol(max_buffer_size_str) > 0) max_buffer_size = std::atol(max_buffer_size_str); @@ -180,13 +173,13 @@ class perfetto_plugin_t { auto* data_source_cfg = trace_cfg.add_data_sources()->mutable_config(); data_source_cfg->set_name("track_event"); - data_source_cfg->set_track_event_config_raw(track_event_cfg.SerializeAsString()); output_prefix_.append(output_file_name + std::to_string(GetPid()) + "_output.pftrace"); file_descriptor_ = open(output_prefix_.string().c_str(), O_RDWR | O_CREAT | O_TRUNC, 0600); if (file_descriptor_ == -1) rocprofiler::warning("Can't open output file\n"); tracing_session_ = perfetto::Tracing::NewTrace(); + trace_cfg.set_unique_session_name(output_prefix_.string()); tracing_session_->Setup(trace_cfg, file_descriptor_); tracing_session_->StartBlocking(); @@ -199,10 +192,12 @@ class perfetto_plugin_t { is_valid_ = true; } - ~perfetto_plugin_t() { - if (is_valid_) { + void delete_perfetto_plugin() { + if (is_valid_ && tracing_session_ && internal_buffer_finished.load(std::memory_order_acquire)) { + writing_lock.lock(); tracing_session_->StopBlocking(); - close(file_descriptor_); + // close(file_descriptor_); + writing_lock.unlock(); } } @@ -236,6 +231,8 @@ class perfetto_plugin_t { // ToDO: rename this variable? if (!tracing_session_) rocprofiler::warning("Tracing session is deleted!\n"); + writing_lock.lock(); + const uint64_t device_id = profiler_record.gpu_id.handle; const uint64_t queue_id = profiler_record.queue_id.handle; const uint64_t correlation_id = profiler_record.correlation_id.value; @@ -246,14 +243,9 @@ class perfetto_plugin_t { device_track_it = device_tracks.find(device_track_id); if (device_track_it == device_tracks.end()) { /* Create a new perfetto::Track (Sub-Track) */ - device_track_it = device_tracks.emplace( - device_track_id, - perfetto::ProcessTrack::Current() - ).first; + device_track_it = device_tracks.emplace(device_track_id, perfetto::Track(device_track_id, perfetto::ProcessTrack::Current())).first; auto gpu_desc = device_track_it->second.Serialize(); gpu_desc.mutable_process()->set_pid(device_id); - gpu_desc.mutable_process()->set_chrome_process_type( - perfetto::protos::gen::ProcessDescriptor::PROCESS_GPU); gpu_desc.mutable_process()->set_process_name("Node: " + hostname_ + " Device: "); perfetto::TrackEvent::SetTrackDescriptor(device_track_it->second, gpu_desc); track_ids_used_.emplace_back(device_track_id); @@ -328,12 +320,14 @@ class perfetto_plugin_t { TRACE_COUNTER("COUNTERS", counters_track, profiler_record.timestamps.end.value, 0); } + writing_lock.unlock(); return 0; } int FlushTracerRecord(rocprofiler_record_tracer_t tracer_record, rocprofiler_session_id_t session_id) { if (!tracing_session_) rocprofiler::warning("Tracing session is deleted!\n"); + writing_lock.lock(); uint64_t device_id = tracer_record.agent_id.handle; std::string kernel_name; const char* operation_name_c = nullptr; @@ -356,12 +350,7 @@ class perfetto_plugin_t { thread_track_it = thread_tracks_.find(thread_track_id); if (thread_track_it == thread_tracks_.end()) { thread_track_it = thread_tracks_.emplace(thread_track_id, - perfetto::Track(thread_track_id, perfetto::ProcessTrack::Current())).first; - - auto thread_track_desc = thread_track_it->second.Serialize(); - thread_track_desc.mutable_process()->set_pid(thread_id); - thread_track_desc.mutable_process()->set_process_name("Thread: "); - perfetto::TrackEvent::SetTrackDescriptor(thread_track_it->second, thread_track_desc); + perfetto::ThreadTrack::ForThread(thread_track_id)).first; track_ids_used_.emplace_back(thread_track_id); } } @@ -381,12 +370,10 @@ class perfetto_plugin_t { /* Create a new perfetto::Track (Sub-Track) */ device_track_it = device_tracks.emplace( device_track_id, - perfetto::ProcessTrack::Current() + perfetto::Track(device_track_id, perfetto::ProcessTrack::Current()) ).first; auto gpu_desc = device_track_it->second.Serialize(); gpu_desc.mutable_process()->set_pid(device_id); - gpu_desc.mutable_process()->set_chrome_process_type( - perfetto::protos::gen::ProcessDescriptor::PROCESS_GPU); gpu_desc.mutable_process()->set_process_name("Node: " + hostname_ + " Device: "); perfetto::TrackEvent::SetTrackDescriptor(device_track_it->second, gpu_desc); track_ids_used_.emplace_back(device_track_id); @@ -523,33 +510,32 @@ class perfetto_plugin_t { break; } case ACTIVITY_DOMAIN_HIP_OPS: { - std::string::size_type pos = std::string::npos; + std::size_t pos = std::string::npos; if (tracer_record.name) { - kernel_name = rocprofiler::truncate_name(rocprofiler::cxx_demangle(tracer_record.name)); TRACE_EVENT_BEGIN( - "HIP_OPS", perfetto::DynamicString(rocprofiler::truncate_name(kernel_name).c_str()), + "HIP_OPS", perfetto::DynamicString(rocprofiler::cxx_demangle(tracer_record.name)), gpu_track, tracer_record.timestamps.begin.value, "Agent ID", - tracer_record.agent_id.handle, "Process ID", GetPid(), "Kernel Name", kernel_name, + tracer_record.agent_id.handle, "Process ID", GetPid(), perfetto::Flow::ProcessScoped(tracer_record.correlation_id.value)); + TRACE_EVENT_END("HIP_OPS", gpu_track, tracer_record.timestamps.end.value); } else { // MEM Copies are not correlated to GPUs, so they need a special track pos = operation_name_c ? std::string_view(operation_name_c).find("Copy") : std::string::npos; - if (std::string::npos == pos) + if (std::string::npos == pos) { TRACE_EVENT_BEGIN("HIP_OPS", perfetto::DynamicString(operation_name_c), gpu_track, tracer_record.timestamps.begin.value, "Process ID", GetPid(), perfetto::Flow::ProcessScoped(tracer_record.correlation_id.value)); - else + TRACE_EVENT_END("HIP_OPS", gpu_track, tracer_record.timestamps.end.value); + } else { TRACE_EVENT_BEGIN("MEM_COPIES", perfetto::DynamicString(operation_name_c), mem_copies_track, tracer_record.timestamps.begin.value, "Process ID", GetPid(), perfetto::Flow::ProcessScoped(tracer_record.correlation_id.value)); + TRACE_EVENT_END("MEM_COPIES", mem_copies_track, tracer_record.timestamps.end.value); + } } - if (std::string::npos == pos) - TRACE_EVENT_END("HIP_OPS", gpu_track, tracer_record.timestamps.end.value); - else - TRACE_EVENT_END("MEM_COPIES", mem_copies_track, tracer_record.timestamps.end.value); break; } case ACTIVITY_DOMAIN_HSA_OPS: { @@ -564,6 +550,7 @@ class perfetto_plugin_t { break; } } + writing_lock.unlock(); return 0; } @@ -592,18 +579,21 @@ class perfetto_plugin_t { } rocprofiler_next_record(begin, &begin, session_id, buffer_id); } + internal_buffer_finished.exchange(true, std::memory_order_acq_rel); return 0; } bool IsValid() const { return is_valid_; } private: - fs::path output_prefix_; std::unique_ptr tracing_session_; + fs::path output_prefix_; int file_descriptor_; bool is_valid_{false}; size_t roctx_track_entries_{0}; + std::atomic internal_buffer_finished{false}; + // Correlate stream id(s) with correlation id(s) to identify the stream id of every HIP activity std::unordered_map stream_ids_; @@ -647,37 +637,39 @@ perfetto_plugin_t* perfetto_plugin = nullptr; } // namespace -static std::mutex writing_lock; - int rocprofiler_plugin_initialize(uint32_t rocprofiler_major_version, uint32_t rocprofiler_minor_version, void* data) { if (rocprofiler_major_version != ROCPROFILER_VERSION_MAJOR || rocprofiler_minor_version > ROCPROFILER_VERSION_MINOR) return -1; - std::lock_guard lock(writing_lock); + // std::lock_guard lock(writing_lock); + writing_lock.lock(); if (perfetto_plugin != nullptr) return -1; perfetto_plugin = new perfetto_plugin_t(); - if (perfetto_plugin->IsValid()) return 0; + if (perfetto_plugin->IsValid()) { + writing_lock.unlock(); + return 0; + } - delete perfetto_plugin; - perfetto_plugin = nullptr; + // delete perfetto_plugin; + // perfetto_plugin = nullptr; + writing_lock.unlock(); return -1; } void rocprofiler_plugin_finalize() { - std::lock_guard lock(writing_lock); if (!perfetto_plugin) return; - delete perfetto_plugin; - perfetto_plugin = nullptr; + perfetto_plugin->delete_perfetto_plugin(); + // delete perfetto_plugin; + // perfetto_plugin = nullptr; } ROCPROFILER_EXPORT int rocprofiler_plugin_write_buffer_records( const rocprofiler_record_header_t* begin, const rocprofiler_record_header_t* end, rocprofiler_session_id_t session_id, rocprofiler_buffer_id_t buffer_id) { - std::lock_guard lock(writing_lock); if (!perfetto_plugin || !perfetto_plugin->IsValid()) return -1; return perfetto_plugin->WriteBufferRecords(begin, end, session_id, buffer_id); @@ -686,8 +678,6 @@ ROCPROFILER_EXPORT int rocprofiler_plugin_write_buffer_records( ROCPROFILER_EXPORT int rocprofiler_plugin_write_record(rocprofiler_record_tracer_t record) { if (record.header.id.handle == 0) return 0; - std::lock_guard lock(writing_lock); - if (!perfetto_plugin || !perfetto_plugin->IsValid()) return -1; return perfetto_plugin->FlushTracerRecord(record, rocprofiler_session_id_t{0}); } diff --git a/plugin/perfetto/perfetto_sdk/CMakeLists.txt b/plugin/perfetto/perfetto_sdk/CMakeLists.txt deleted file mode 100644 index 385d0820fe..0000000000 --- a/plugin/perfetto/perfetto_sdk/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -set(CMAKE_CXX_CLANG_TIDY) -set(CMAKE_POSITION_INDEPENDENT_CODE ON) - -add_library(rocprofiler-perfetto-sdk STATIC sdk/perfetto.h sdk/perfetto.cc) -add_library(rocprofiler::perfetto-sdk ALIAS rocprofiler-perfetto-sdk) - -target_include_directories(rocprofiler-perfetto-sdk - PUBLIC $) diff --git a/plugin/perfetto/perfetto_sdk/LICENSE b/plugin/perfetto/perfetto_sdk/LICENSE deleted file mode 100644 index bb056df223..0000000000 --- a/plugin/perfetto/perfetto_sdk/LICENSE +++ /dev/null @@ -1,189 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright (c) 2017, The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - diff --git a/plugin/perfetto/perfetto_sdk/OWNERS b/plugin/perfetto/perfetto_sdk/OWNERS deleted file mode 100644 index 0da623cfe7..0000000000 --- a/plugin/perfetto/perfetto_sdk/OWNERS +++ /dev/null @@ -1,35 +0,0 @@ -# Global OWNERS that can approve Perfetto changes. -# Please look first at OWNERS in the various subdirectories before falling back -# on this, as the former tend to be more brain-cache-hot. - -# Perfetto tracing internals and API/ABI boundaries. -primiano@google.com -skyostil@google.com - -# UI, Ftrace interop, traced_probes, protozero, Android internals. -hjd@google.com - -# Trace Processor, metrics, infra. -lalitm@google.com - -# Callstack / memory profilers, traced_probes & Linux internals. -ddiproietto@google.com -rsavitski@google.com - -# Chromium-related things and tracing SDK. -eseckler@google.com -nuskos@google.com -oysteine@google.com - -# Most Android-related metrics. -ilkos@google.com - -# fmayer@ left the team. Please try first rsavitski@, ddiproietto@ or primiano@ -# and leave fmayer@ as an emergency-only escalation on profilers. -fmayer@google.com - -# chromium.org aliases for adding DEPS entries from chromium subprojects to -# third_party/perfetto. -eseckler@chromium.org -nuskos@chromium.org -skyostil@chromium.org diff --git a/plugin/perfetto/perfetto_sdk/docs/tracing-sdk.md b/plugin/perfetto/perfetto_sdk/docs/tracing-sdk.md deleted file mode 100644 index 856dc378a1..0000000000 --- a/plugin/perfetto/perfetto_sdk/docs/tracing-sdk.md +++ /dev/null @@ -1,394 +0,0 @@ -# Tracing SDK - -The Perfetto Tracing SDK is a C++11 library that allows userspace applications -to emit trace events and add more app-specific context to a Perfetto trace. - -When using the Tracing SDK there are two main aspects to consider: - -1. Whether you are interested only in tracing events coming from your own app - or want to collect full-stack traces that overlay app trace events with - system trace events like scheduler traces, syscalls or any other Perfetto - data source. - -2. For app-specific tracing, whether you need to trace simple types of timeline - events (e.g., slices, counters) or need to define complex data sources with a - custom strongly-typed schema (e.g., for dumping the state of a subsystem of - your app into the trace). - -For Android-only instrumentation, the advice is to keep using the existing -[android.os.Trace (SDK)][atrace-sdk] / [ATrace_* (NDK)][atrace-ndk] if they -are sufficient for your use cases. Atrace-based instrumentation is fully -supported in Perfetto. -See the [Data Sources -> Android System -> Atrace Instrumentation][atrace-ds] -for details. - -## Getting started - -TIP: The code from these examples is also available [in the -repository](/examples/sdk/README.md). - -To start using the Client API, first check out the latest SDK release: - -```bash -git clone https://android.googlesource.com/platform/external/perfetto -b v23.0 -``` - -The SDK consists of two files, `sdk/perfetto.h` and `sdk/perfetto.cc`. These are -an amalgamation of the Client API designed to easy to integrate to existing -build systems. The sources are self-contained and require only a C++11 compliant -standard library. - -For example, to add the SDK to a CMake project, edit your CMakeLists.txt: - -```cmake -cmake_minimum_required(VERSION 3.13) -project(PerfettoExample) -find_package(Threads) - -# Define a static library for Perfetto. -include_directories(perfetto/sdk) -add_library(perfetto STATIC perfetto/sdk/perfetto.cc) - -# Link the library to your main executable. -add_executable(example example.cc) -target_link_libraries(example perfetto ${CMAKE_THREAD_LIBS_INIT}) -``` - -Next, initialize Perfetto in your program: - -```C++ -#include - -int main(int argc, char** argv) { - perfetto::TracingInitArgs args; - - // The backends determine where trace events are recorded. You may select one - // or more of: - - // 1) The in-process backend only records within the app itself. - args.backends |= perfetto::kInProcessBackend; - - // 2) The system backend writes events into a system Perfetto daemon, - // allowing merging app and system events (e.g., ftrace) on the same - // timeline. Requires the Perfetto `traced` daemon to be running (e.g., - // on Android Pie and newer). - args.backends |= perfetto::kSystemBackend; - - perfetto::Tracing::Initialize(args); -} -``` - -You are now ready to instrument your app with trace events. - -## Custom data sources vs Track events - -The SDK offers two abstraction layers to inject tracing data, built on top of -each other, which trade off code complexity vs expressive power: -[track events](#track-events) and [custom data sources](#custom-data-sources). - -### Track events - -Track events are the suggested option when dealing with app-specific tracing as -they take care of a number of subtleties (e.g., thread safety, flushing, string -interning). -Track events are time bounded events (e.g., slices, counter) based on simple -`TRACE_EVENT` annotation tags in the codebase, like this: - -```c++ -#include - -PERFETTO_DEFINE_CATEGORIES( - perfetto::Category("rendering") - .SetDescription("Events from the graphics subsystem"), - perfetto::Category("network") - .SetDescription("Network upload and download statistics")); - -... - -int main(int argc, char** argv) { - ... - perfetto::Tracing::Initialize(args); - perfetto::TrackEvent::Register(); -} - -... - -void LayerTreeHost::DoUpdateLayers() { - TRACE_EVENT("rendering", "LayerTreeHost::DoUpdateLayers"); - ... - for (PictureLayer& pl : layers) { - TRACE_EVENT("rendering", "PictureLayer::Update"); - pl.Update(); - } -} -``` - -Which are rendered in the UI as follows: - -![Track event example](/docs/images/track-events.png) - -Track events are the best default option and serve most tracing use cases with -very little complexity. - -To include your new track events in the trace, ensure that the `track_event` -data source is included in the trace config. If you do not specify any -categories then all non-debug categories will be included by default. However, -you can also add just the categories you are interested in like so: - -```protobuf -data_sources { - config { - name: "track_event" - track_event_config { - enabled_categories: "rendering" - } - } -} -``` - -See the [Track events page](track-events.md) for full instructions. - -### Custom data sources - -For most uses, track events are the most straightforward way of instrumenting -apps for tracing. However, in some rare circumstances they are not -flexible enough, e.g., when the data doesn't fit the notion of a track or is -high volume enough that it needs a strongly typed schema to minimize the size of -each event. In this case, you can implement a *custom data source* for -Perfetto. - -Unlike track events, when working with custom data sources, you will also need -corresponding changes in [trace processor](/docs/analysis/trace-processor.md) -to enable importing your data format. - -A custom data source is a subclass of `perfetto::DataSource`. Perfetto will -automatically create one instance of the class for each tracing session it is -active in (usually just one). - -```C++ -class CustomDataSource : public perfetto::DataSource { - public: - void OnSetup(const SetupArgs&) override { - // Use this callback to apply any custom configuration to your data source - // based on the TraceConfig in SetupArgs. - } - - void OnStart(const StartArgs&) override { - // This notification can be used to initialize the GPU driver, enable - // counters, etc. StartArgs will contains the DataSourceDescriptor, - // which can be extended. - } - - void OnStop(const StopArgs&) override { - // Undo any initialization done in OnStart. - } - - // Data sources can also have per-instance state. - int my_custom_state = 0; -}; - -PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS(CustomDataSource); -``` - -The data source's static data should be defined in one source file like this: - -```C++ -PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(CustomDataSource); -``` - -Custom data sources need to be registered with Perfetto: - -```C++ -int main(int argc, char** argv) { - ... - perfetto::Tracing::Initialize(args); - // Add the following: - perfetto::DataSourceDescriptor dsd; - dsd.set_name("com.example.custom_data_source"); - CustomDataSource::Register(dsd); -} -``` - -As with all data sources, the custom data source needs to be specified in the -trace config to enable tracing: - -```C++ -perfetto::TraceConfig cfg; -auto* ds_cfg = cfg.add_data_sources()->mutable_config(); -ds_cfg->set_name("com.example.custom_data_source"); -``` - -Finally, call the `Trace()` method to record an event with your custom data -source. The lambda function passed to that method will only be called if tracing -is enabled. It is always called synchronously and possibly multiple times if -multiple concurrent tracing sessions are active. - -```C++ -CustomDataSource::Trace([](CustomDataSource::TraceContext ctx) { - auto packet = ctx.NewTracePacket(); - packet->set_timestamp(perfetto::TrackEvent::GetTraceTimeNs()); - packet->set_for_testing()->set_str("Hello world!"); -}); -``` - -If necessary the `Trace()` method can access the custom data source state -(`my_custom_state` in the example above). Doing so, will take a mutex to -ensure data source isn't destroyed (e.g., because of stopping tracing) while -the `Trace()` method is called on another thread. For example: - -```C++ -CustomDataSource::Trace([](CustomDataSource::TraceContext ctx) { - auto safe_handle = trace_args.GetDataSourceLocked(); // Holds a RAII lock. - DoSomethingWith(safe_handle->my_custom_state); -}); -``` - -## In-process vs System mode - -The two modes are not mutually exclusive. An app can be configured to work -in both modes and respond both to in-process tracing requests and system -tracing requests. Both modes generate the same trace file format. - -### In-process mode - -In this mode both the perfetto service and the app-defined data sources are -hosted fully in-process, in the same process of the profiled app. No connection -to the system `traced` daemon will be attempted. - -In-process mode can be enabled by setting -`TracingInitArgs.backends = perfetto::kInProcessBackend` when initializing the -SDK, see examples below. - -This mode is used to generate traces that contain only events emitted by -the app, but not other types of events (e.g. scheduler traces). - -The main advantage is that by running fully in-process, it doesn't require any -special OS privileges and the profiled process can control the lifecycle of -tracing sessions. - -This mode is supported on Android, Linux, MacOS and Windows. - -### System mode - -In this mode the app-defined data sources will connect to the external `traced` -service using the [IPC over UNIX socket][ipc]. - -System mode can be enabled by setting -`TracingInitArgs.backends = perfetto::kSystemBackend` when initializing the SDK, -see examples below. - -The main advantage of this mode is that it is possible to create fused traces where -app events are overlaid on the same timeline of OS events. This enables -full-stack performance investigations, looking all the way through syscalls and -kernel scheduling events. - -The main limitation of this mode is that it requires the external `traced` daemon -to be up and running and reachable through the UNIX socket connection. - -This is suggested for local debugging or lab testing scenarios where the user -(or the test harness) can control the OS deployment (e.g., sideload binaries on -Android). - -When using system mode, the tracing session must be controlled from the outside, -using the `perfetto` command-line client -(See [reference](/docs/reference/perfetto-cli)). This is because when collecting -system traces, tracing data producers are not allowed to read back the trace -data as it might disclose information about other processes and allow -side-channel attacks. - -* On Android 9 (Pie) and beyond, traced is shipped as part of the platform. -* On older versions of Android, traced can be built from sources using the - the [standalone NDK-based workflow](/docs/contributing/build-instructions.md) - and sideloaded via adb shell. -* On Linux and MacOS `traced` must be built and run separately. See the - [Linux quickstart](/docs/quickstart/linux-tracing.md) for instructions. - -_System mode is not yet supported on Windows, due to the lack of an IPC -implementation_. - -## {#recording} Recording traces through the API - -_Tracing through the API is currently only supported with the in-process mode. -When using system mode, use the `perfetto` cmdline client (see quickstart -guides)._ - -First initialize a [TraceConfig](/docs/reference/trace-config-proto.autogen) -message which specifies what type of data to record. - -If your app includes [track events](track-events.md) (i.e, `TRACE_EVENT`), you -typically want to choose the categories which are enabled for tracing. - -By default, all non-debug categories are enabled, but you can enable a specific -one like this: - -```C++ -perfetto::protos::gen::TrackEventConfig track_event_cfg; -track_event_cfg.add_disabled_categories("*"); -track_event_cfg.add_enabled_categories("rendering"); -``` - -Next, build the main trace config together with the track event part: - -```C++ -perfetto::TraceConfig cfg; -cfg.add_buffers()->set_size_kb(1024); // Record up to 1 MiB. -auto* ds_cfg = cfg.add_data_sources()->mutable_config(); -ds_cfg->set_name("track_event"); -ds_cfg->set_track_event_config_raw(track_event_cfg.SerializeAsString()); -``` - -If your app includes a custom data source, you can also enable it here: - -```C++ -ds_cfg = cfg.add_data_sources()->mutable_config(); -ds_cfg->set_name("my_data_source"); -``` - -After building the trace config, you can begin tracing: - -```C++ -std::unique_ptr tracing_session( - perfetto::Tracing::NewTrace()); -tracing_session->Setup(cfg); -tracing_session->StartBlocking(); -``` - -TIP: API methods with `Blocking` in their name will suspend the calling thread - until the respective operation is complete. There are also asynchronous - variants that don't have this limitation. - -Now that tracing is active, instruct your app to perform the operation you -want to record. After that, stop tracing and collect the -protobuf-formatted trace data: - -```C++ -tracing_session->StopBlocking(); -std::vector trace_data(tracing_session->ReadTraceBlocking()); - -// Write the trace into a file. -std::ofstream output; -output.open("example.perfetto-trace", std::ios::out | std::ios::binary); -output.write(&trace_data[0], trace_data.size()); -output.close(); -``` - -To save memory with longer traces, you can also tell Perfetto to write -directly into a file by passing a file descriptor into Setup(), remembering -to close the file after tracing is done: - -```C++ -int fd = open("example.perfetto-trace", O_RDWR | O_CREAT | O_TRUNC, 0600); -tracing_session->Setup(cfg, fd); -tracing_session->StartBlocking(); -// ... -tracing_session->StopBlocking(); -close(fd); -``` - -The resulting trace file can be directly opened in the [Perfetto -UI](https://ui.perfetto.dev) or the [Trace Processor](/docs/analysis/trace-processor.md). - -[ipc]: /docs/design-docs/api-and-abi.md#socket-protocol -[atrace-ds]: /docs/data-sources/atrace.md -[atrace-ndk]: https://developer.android.com/ndk/reference/group/tracing -[atrace-sdk]: https://developer.android.com/reference/android/os/Trace diff --git a/plugin/perfetto/perfetto_sdk/sdk/perfetto.cc b/plugin/perfetto/perfetto_sdk/sdk/perfetto.cc deleted file mode 100644 index 9ece1fb2cd..0000000000 --- a/plugin/perfetto/perfetto_sdk/sdk/perfetto.cc +++ /dev/null @@ -1,80065 +0,0 @@ -// Copyright (C) 2019 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file is automatically generated by gen_amalgamated. Do not edit. - -// gen_amalgamated: predefined macros -#if !defined(PERFETTO_IMPLEMENTATION) -#define PERFETTO_IMPLEMENTATION -#endif -#include "perfetto.h" -// gen_amalgamated begin source: src/base/default_platform.cc -// gen_amalgamated begin header: include/perfetto/ext/base/platform.h -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INCLUDE_PERFETTO_EXT_BASE_PLATFORM_H_ -#define INCLUDE_PERFETTO_EXT_BASE_PLATFORM_H_ - -namespace perfetto { -namespace base { -namespace platform { - -// Executed before entering a syscall (e.g. poll, read, write etc) which might -// block. -// This is overridden in Google internal builds for dealing with userspace -// scheduling. -void BeforeMaybeBlockingSyscall(); - -// Executed after entering a syscall (e.g. poll, read, write etc) which might -// block. -// This is overridden in Google internal builds for dealing with userspace -// scheduling. -void AfterMaybeBlockingSyscall(); - -} // namespace platform -} // namespace base -} // namespace perfetto - -#endif // INCLUDE_PERFETTO_EXT_BASE_PLATFORM_H_ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// gen_amalgamated expanded: #include "perfetto/ext/base/platform.h" - -namespace perfetto { -namespace base { -namespace platform { - -// This is a no-op outside of Google3 where we have some custom logic to deal -// with the userspace scheduler. -void BeforeMaybeBlockingSyscall() {} - -// This is a no-op outside of Google3 where we have some custom logic to deal -// with the userspace scheduler. -void AfterMaybeBlockingSyscall() {} - -} // namespace platform -} // namespace base -} // namespace perfetto -// gen_amalgamated begin source: src/base/android_utils.cc -// gen_amalgamated begin header: include/perfetto/ext/base/android_utils.h -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INCLUDE_PERFETTO_EXT_BASE_ANDROID_UTILS_H_ -#define INCLUDE_PERFETTO_EXT_BASE_ANDROID_UTILS_H_ - -#include - -// gen_amalgamated expanded: #include "perfetto/base/build_config.h" - -namespace perfetto { -namespace base { - -#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) - -// Returns the value of the Android system property named `name`. If the -// property does not exist, returns an empty string (a non-existing property is -// the same as a property with an empty value for this API). -std::string GetAndroidProp(const char* name); - -#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) - -} // namespace base -} // namespace perfetto - -#endif // INCLUDE_PERFETTO_EXT_BASE_ANDROID_UTILS_H_ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// gen_amalgamated expanded: #include "perfetto/ext/base/android_utils.h" - -// gen_amalgamated expanded: #include "perfetto/base/build_config.h" - -#include - -#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) -#include -#endif - -// gen_amalgamated expanded: #include "perfetto/base/compiler.h" -// gen_amalgamated expanded: #include "perfetto/base/logging.h" - -namespace perfetto { -namespace base { - -#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) - -std::string GetAndroidProp(const char* name) { - std::string ret; -#if __ANDROID_API__ >= 26 - const prop_info* pi = __system_property_find(name); - if (!pi) { - return ret; - } - __system_property_read_callback( - pi, - [](void* dst_void, const char*, const char* value, uint32_t) { - std::string& dst = *static_cast(dst_void); - dst = value; - }, - &ret); -#else // __ANDROID_API__ < 26 - char value_buf[PROP_VALUE_MAX]; - int len = __system_property_get(name, value_buf); - if (len > 0 && static_cast(len) < sizeof(value_buf)) { - ret = std::string(value_buf, static_cast(len)); - } -#endif - return ret; -} - -#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) - -} // namespace base -} // namespace perfetto -// gen_amalgamated begin source: src/base/base64.cc -// gen_amalgamated begin header: include/perfetto/ext/base/base64.h -// gen_amalgamated begin header: include/perfetto/ext/base/string_view.h -// gen_amalgamated begin header: include/perfetto/ext/base/hash.h -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INCLUDE_PERFETTO_EXT_BASE_HASH_H_ -#define INCLUDE_PERFETTO_EXT_BASE_HASH_H_ - -#include -#include -#include -#include -#include - -namespace perfetto { -namespace base { - -// A helper class which computes a 64-bit hash of the input data. -// The algorithm used is FNV-1a as it is fast and easy to implement and has -// relatively few collisions. -// WARNING: This hash function should not be used for any cryptographic purpose. -class Hasher { - public: - // Creates an empty hash object - Hasher() {} - - // Hashes a numeric value. - template ::value, bool>::type = true> - void Update(T data) { - Update(reinterpret_cast(&data), sizeof(data)); - } - - // Using the loop instead of "Update(str, strlen(str))" to avoid looping twice - void Update(const char* str) { - for (const auto* p = str; *p; ++p) Update(*p); - } - - // Hashes a byte array. - void Update(const char* data, size_t size) { - for (size_t i = 0; i < size; i++) { - result_ ^= static_cast(data[i]); - // Note: Arithmetic overflow of unsigned integers is well defined in C++ - // standard unlike signed integers. - // https://stackoverflow.com/a/41280273 - result_ *= kFnv1a64Prime; - } - } - - // Allow hashing anything that has a |data| field, a |size| field, - // and has the kHashable trait (e.g., base::StringView). - template > void Update(const T& t) { - Update(t.data(), t.size()); - } - - void Update(const std::string& s) { Update(s.data(), s.size()); } - - uint64_t digest() const { return result_; } - - // Usage: - // uint64_t hashed_value = Hash::Combine(33, false, "ABC", 458L, 3u, 'x'); - template static uint64_t Combine(Ts&&... args) { - Hasher hasher; - hasher.UpdateAll(std::forward(args)...); - return hasher.digest(); - } - - // `hasher.UpdateAll(33, false, "ABC")` is shorthand for: - // `hasher.Update(33); hasher.Update(false); hasher.Update("ABC");` - void UpdateAll() {} - - template void UpdateAll(T&& arg, Ts&&... args) { - Update(arg); - UpdateAll(std::forward(args)...); - } - - private: - static constexpr uint64_t kFnv1a64OffsetBasis = 0xcbf29ce484222325; - static constexpr uint64_t kFnv1a64Prime = 0x100000001b3; - - uint64_t result_ = kFnv1a64OffsetBasis; -}; - -// This is for using already-hashed key into std::unordered_map and avoid the -// cost of re-hashing. Example: -// unordered_map my_map. -template struct AlreadyHashed { - size_t operator()(const T& x) const { return static_cast(x); } -}; - -// base::Hash uses base::Hasher for integer values and falls base to std::hash -// for other types. This is needed as std::hash for integers is just the -// identity function and Perfetto uses open-addressing hash table, which are -// very sensitive to hash quality and are known to degrade in performance -// when using std::hash. -template struct Hash { - // Version for ints, using base::Hasher. - template - auto operator()(const U& x) -> - typename std::enable_if::value, size_t>::type const { - Hasher hash; - hash.Update(x); - return static_cast(hash.digest()); - } - - // Version for non-ints, falling back to std::hash. - template - auto operator()(const U& x) -> - typename std::enable_if::value, size_t>::type const { - return std::hash()(x); - } -}; - -} // namespace base -} // namespace perfetto - -#endif // INCLUDE_PERFETTO_EXT_BASE_HASH_H_ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_H_ -#define INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_H_ - -#include - -#include -#include - -// gen_amalgamated expanded: #include "perfetto/base/build_config.h" -// gen_amalgamated expanded: #include "perfetto/base/logging.h" -// gen_amalgamated expanded: #include "perfetto/ext/base/hash.h" - -namespace perfetto { -namespace base { - -// A string-like object that refers to a non-owned piece of memory. -// Strings are internally NOT null terminated. -class StringView { - public: - // Allow hashing with base::Hash. - static constexpr bool kHashable = true; - static constexpr size_t npos = static_cast(-1); - - StringView() : data_(nullptr), size_(0) {} - StringView(const StringView&) = default; - StringView& operator=(const StringView&) = default; - StringView(const char* data, size_t size) : data_(data), size_(size) { - PERFETTO_DCHECK(size == 0 || data != nullptr); - } - - // Allow implicit conversion from any class that has a |data| and |size| field - // and has the kConvertibleToStringView trait (e.g., protozero::ConstChars). - template > - StringView(const T& x) : StringView(x.data, x.size) { - PERFETTO_DCHECK(x.size == 0 || x.data != nullptr); - } - - // Creates a StringView from a null-terminated C string. - // Deliberately not "explicit". - StringView(const char* cstr) : data_(cstr), size_(strlen(cstr)) { - PERFETTO_DCHECK(cstr != nullptr); - } - - // This instead has to be explicit, as creating a StringView out of a - // std::string can be subtle. - explicit StringView(const std::string& str) : data_(str.data()), size_(str.size()) {} - - bool empty() const { return size_ == 0; } - size_t size() const { return size_; } - const char* data() const { return data_; } - const char* begin() const { return data_; } - const char* end() const { return data_ + size_; } - - char at(size_t pos) const { - PERFETTO_DCHECK(pos < size_); - return data_[pos]; - } - - size_t find(char c, size_t start_pos = 0) const { - for (size_t i = start_pos; i < size_; ++i) { - if (data_[i] == c) return i; - } - return npos; - } - - size_t find(const StringView& str, size_t start_pos = 0) const { - if (start_pos > size()) return npos; - auto it = std::search(begin() + start_pos, end(), str.begin(), str.end()); - size_t pos = static_cast(it - begin()); - return pos + str.size() <= size() ? pos : npos; - } - - size_t find(const char* str, size_t start_pos = 0) const { - return find(StringView(str), start_pos); - } - - size_t rfind(char c) const { - for (size_t i = size_; i > 0; --i) { - if (data_[i - 1] == c) return i - 1; - } - return npos; - } - - StringView substr(size_t pos, size_t count = npos) const { - if (pos >= size_) return StringView("", 0); - size_t rcount = std::min(count, size_ - pos); - return StringView(data_ + pos, rcount); - } - - bool CaseInsensitiveEq(const StringView& other) const { - if (size() != other.size()) return false; - if (size() == 0) return true; -#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) - return _strnicmp(data(), other.data(), size()) == 0; -#else - return strncasecmp(data(), other.data(), size()) == 0; -#endif - } - - bool StartsWith(const StringView& other) const { - if (other.size() == 0) return true; - if (size() == 0) return false; - if (other.size() > size()) return false; - return memcmp(data(), other.data(), other.size()) == 0; - } - - bool EndsWith(const StringView& other) const { - if (other.size() == 0) return true; - if (size() == 0) return false; - if (other.size() > size()) return false; - size_t off = size() - other.size(); - return memcmp(data() + off, other.data(), other.size()) == 0; - } - - std::string ToStdString() const { return size_ == 0 ? "" : std::string(data_, size_); } - - uint64_t Hash() const { - base::Hasher hasher; - hasher.Update(data_, size_); - return hasher.digest(); - } - - private: - const char* data_ = nullptr; - size_t size_ = 0; -}; - -inline bool operator==(const StringView& x, const StringView& y) { - if (x.size() != y.size()) return false; - if (x.size() == 0) return true; - return memcmp(x.data(), y.data(), x.size()) == 0; -} - -inline bool operator!=(const StringView& x, const StringView& y) { return !(x == y); } - -inline bool operator<(const StringView& x, const StringView& y) { - auto size = std::min(x.size(), y.size()); - if (size == 0) return x.size() < y.size(); - int result = memcmp(x.data(), y.data(), size); - return result < 0 || (result == 0 && x.size() < y.size()); -} - -inline bool operator>=(const StringView& x, const StringView& y) { return !(x < y); } - -inline bool operator>(const StringView& x, const StringView& y) { return y < x; } - -inline bool operator<=(const StringView& x, const StringView& y) { return !(y < x); } - -} // namespace base -} // namespace perfetto - -template <> struct std::hash<::perfetto::base::StringView> { - size_t operator()(const ::perfetto::base::StringView& sv) const { - return static_cast(sv.Hash()); - } -}; - -#endif // INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_H_ -// gen_amalgamated begin header: include/perfetto/ext/base/utils.h -// gen_amalgamated begin header: include/perfetto/ext/base/sys_types.h -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INCLUDE_PERFETTO_EXT_BASE_SYS_TYPES_H_ -#define INCLUDE_PERFETTO_EXT_BASE_SYS_TYPES_H_ - -// This headers deals with sys types commonly used in the codebase that are -// missing on Windows. - -#include - -// gen_amalgamated expanded: #include "perfetto/base/build_config.h" - -#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) - -#if !PERFETTO_BUILDFLAG(PERFETTO_COMPILER_GCC) -// MinGW has these. clang-cl and MSVC, which use just the Windows SDK, don't. -using uid_t = unsigned int; -using pid_t = int; -#endif // !GCC - -#if defined(_WIN64) -using ssize_t = int64_t; -#else -using ssize_t = long; -#endif // _WIN64 - -#endif // OS_WIN - -namespace perfetto { -namespace base { - -constexpr uid_t kInvalidUid = static_cast(-1); -constexpr pid_t kInvalidPid = static_cast(-1); - -} // namespace base -} // namespace perfetto - -#endif // INCLUDE_PERFETTO_EXT_BASE_SYS_TYPES_H_ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INCLUDE_PERFETTO_EXT_BASE_UTILS_H_ -#define INCLUDE_PERFETTO_EXT_BASE_UTILS_H_ - -#include -#include -#include -#include - -#include -#include -#include -#include - -// gen_amalgamated expanded: #include "perfetto/base/build_config.h" -// gen_amalgamated expanded: #include "perfetto/base/compiler.h" -// gen_amalgamated expanded: #include "perfetto/ext/base/sys_types.h" - -#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) -// Even if Windows has errno.h, the all syscall-restart behavior does not apply. -// Trying to handle EINTR can cause more harm than good if errno is left stale. -// Chromium does the same. -#define PERFETTO_EINTR(x) (x) -#else -#define PERFETTO_EINTR(x) \ - ([&] { \ - decltype(x) eintr_wrapper_result; \ - do { \ - eintr_wrapper_result = (x); \ - } while (eintr_wrapper_result == -1 && errno == EINTR); \ - return eintr_wrapper_result; \ - }()) -#endif - -namespace perfetto { -namespace base { - -// Do not add new usages of kPageSize, consider using GetSysPageSize() below. -// TODO(primiano): over time the semantic of kPageSize became too ambiguous. -// Strictly speaking, this constant is incorrect on some new devices where the -// page size can be 16K (e.g., crbug.com/1116576). Unfortunately too much code -// ended up depending on kPageSize for purposes that are not strictly related -// with the kernel's mm subsystem. -constexpr size_t kPageSize = 4096; - -// Returns the system's page size. Use this when dealing with mmap, madvise and -// similar mm-related syscalls. -uint32_t GetSysPageSize(); - -template constexpr size_t ArraySize(const T (&)[TSize]) { return TSize; } - -// Function object which invokes 'free' on its parameter, which must be -// a pointer. Can be used to store malloc-allocated pointers in std::unique_ptr: -// -// std::unique_ptr foo_ptr( -// static_cast(malloc(sizeof(int)))); -struct FreeDeleter { - inline void operator()(void* ptr) const { free(ptr); } -}; - -template constexpr T AssumeLittleEndian(T value) { -#if !PERFETTO_IS_LITTLE_ENDIAN() - static_assert(false, "Unimplemented on big-endian archs"); -#endif - return value; -} - -// Round up |size| to a multiple of |alignment| (must be a power of two). -template constexpr size_t AlignUp(size_t size) { - static_assert((alignment & (alignment - 1)) == 0, "alignment must be a pow2"); - return (size + alignment - 1) & ~(alignment - 1); -} - -inline bool IsAgain(int err) { return err == EAGAIN || err == EWOULDBLOCK; } - -// setenv(2)-equivalent. Deals with Windows vs Posix discrepancies. -void SetEnv(const std::string& key, const std::string& value); - -// unsetenv(2)-equivalent. Deals with Windows vs Posix discrepancies. -void UnsetEnv(const std::string& key); - -// Calls mallopt(M_PURGE, 0) on Android. Does nothing on other platforms. -// This forces the allocator to release freed memory. This is used to work -// around various Scudo inefficiencies. See b/170217718. -void MaybeReleaseAllocatorMemToOS(); - -// geteuid() on POSIX OSes, returns 0 on Windows (See comment in utils.cc). -uid_t GetCurrentUserId(); - -// Forks the process. -// Parent: prints the PID of the child, calls |parent_cb| and exits from the -// process with its return value. -// Child: redirects stdio onto /dev/null, chdirs into / and returns. -void Daemonize(std::function parent_cb); - -// Returns the path of the current executable, e.g. /foo/bar/exe. -std::string GetCurExecutablePath(); - -// Returns the directory where the current executable lives in, e.g. /foo/bar. -// This is independent of cwd(). -std::string GetCurExecutableDir(); - -// Memory returned by AlignedAlloc() must be freed via AlignedFree() not just -// free. It makes a difference on Windows where _aligned_malloc() and -// _aligned_free() must be paired. -// Prefer using the AlignedAllocTyped() below which takes care of the pairing. -void* AlignedAlloc(size_t alignment, size_t size); -void AlignedFree(void*); - -// A RAII version of the above, which takes care of pairing Aligned{Alloc,Free}. -template struct AlignedDeleter { - inline void operator()(T* ptr) const { AlignedFree(ptr); } -}; - -// The remove_extent here and below is to allow defining unique_ptr. -// As per https://en.cppreference.com/w/cpp/memory/unique_ptr the Deleter takes -// always a T*, not a T[]*. -template -using AlignedUniquePtr = std::unique_ptr::type>>; - -template AlignedUniquePtr AlignedAllocTyped(size_t n_membs) { - using TU = typename std::remove_extent::type; - return AlignedUniquePtr(static_cast(AlignedAlloc(alignof(TU), sizeof(TU) * n_membs))); -} - -// A RAII wrapper to invoke a function when leaving a function/scope. -template class OnScopeExitWrapper { - public: - explicit OnScopeExitWrapper(Func f) : f_(std::move(f)), active_(true) {} - OnScopeExitWrapper(OnScopeExitWrapper&& other) noexcept - : f_(std::move(other.f_)), active_(other.active_) { - other.active_ = false; - } - ~OnScopeExitWrapper() { - if (active_) f_(); - } - - private: - Func f_; - bool active_; -}; - -template PERFETTO_WARN_UNUSED_RESULT OnScopeExitWrapper OnScopeExit(Func f) { - return OnScopeExitWrapper(std::move(f)); -} - -// Returns a xxd-style hex dump (hex + ascii chars) of the input data. -std::string HexDump(const void* data, size_t len, size_t bytes_per_line = 16); -inline std::string HexDump(const std::string& data, size_t bytes_per_line = 16) { - return HexDump(data.data(), data.size(), bytes_per_line); -} - -} // namespace base -} // namespace perfetto - -#endif // INCLUDE_PERFETTO_EXT_BASE_UTILS_H_ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INCLUDE_PERFETTO_EXT_BASE_BASE64_H_ -#define INCLUDE_PERFETTO_EXT_BASE_BASE64_H_ - -#include -#include - -// gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h" -// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h" // For ssize_t. - -namespace perfetto { -namespace base { - -// Returns the length of the destination string (included '=' padding). -// Does NOT include the size of the string null terminator. -inline size_t Base64EncSize(size_t src_size) { return (src_size + 2) / 3 * 4; } - -// Returns the upper bound on the length of the destination buffer. -// The actual decoded length might be <= the number returned here. -inline size_t Base64DecSize(size_t src_size) { return (src_size + 3) / 4 * 3; } - -// Does NOT null-terminate |dst|. -ssize_t Base64Encode(const void* src, size_t src_size, char* dst, size_t dst_size); - -std::string Base64Encode(const void* src, size_t src_size); - -inline std::string Base64Encode(StringView sv) { return Base64Encode(sv.data(), sv.size()); } - -// Returns -1 in case of failure. -ssize_t Base64Decode(const char* src, size_t src_size, uint8_t* dst, size_t dst_size); - -std::optional Base64Decode(const char* src, size_t src_size); - -inline std::optional Base64Decode(StringView sv) { - return Base64Decode(sv.data(), sv.size()); -} - -} // namespace base -} // namespace perfetto - -#endif // INCLUDE_PERFETTO_EXT_BASE_BASE64_H_ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// gen_amalgamated expanded: #include "perfetto/ext/base/base64.h" - -namespace perfetto { -namespace base { - -namespace { - -constexpr char kPadding = '='; - -constexpr char kEncTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static_assert(sizeof(kEncTable) == (1u << 6) + sizeof('\0'), "Bad table size"); - -// Maps an ASCII character to its 6-bit value. It only contains translations -// from '+' to 'z'. Supports the standard (+/) and URL-safe (-_) alphabets. -constexpr uint8_t kX = 0xff; // Value used for invalid characters -constexpr uint8_t kDecTable[] = { - 62, kX, 62, kX, 63, 52, 53, 54, 55, 56, // 00 - 09 - 57, 58, 59, 60, 61, kX, kX, kX, 0, kX, // 10 - 19 - kX, kX, 0, 1, 2, 3, 4, 5, 6, 7, // 20 - 29 - 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, // 30 - 39 - 18, 19, 20, 21, 22, 23, 24, 25, kX, kX, // 40 - 49 - kX, kX, 63, kX, 26, 27, 28, 29, 30, 31, // 50 - 59 - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, // 60 - 69 - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // 70 - 79 -}; -constexpr char kMinDecChar = '+'; -constexpr char kMaxDecChar = 'z'; -static_assert(kMaxDecChar - kMinDecChar <= sizeof(kDecTable), "Bad table size"); - -inline uint8_t DecodeChar(char c) { - if (c < kMinDecChar || c > kMaxDecChar) return kX; - return kDecTable[c - kMinDecChar]; -} - -} // namespace - -ssize_t Base64Encode(const void* src, size_t src_size, char* dst, size_t dst_size) { - const size_t padded_dst_size = Base64EncSize(src_size); - if (dst_size < padded_dst_size) return -1; // Not enough space in output. - - const uint8_t* rd = static_cast(src); - const uint8_t* const end = rd + src_size; - size_t wr_size = 0; - while (rd < end) { - uint8_t s[3]{}; - s[0] = *(rd++); - dst[wr_size++] = kEncTable[s[0] >> 2]; - - uint8_t carry0 = static_cast((s[0] & 0x03) << 4); - if (PERFETTO_LIKELY(rd < end)) { - s[1] = *(rd++); - dst[wr_size++] = kEncTable[carry0 | (s[1] >> 4)]; - } else { - dst[wr_size++] = kEncTable[carry0]; - dst[wr_size++] = kPadding; - dst[wr_size++] = kPadding; - break; - } - - uint8_t carry1 = static_cast((s[1] & 0x0f) << 2); - if (PERFETTO_LIKELY(rd < end)) { - s[2] = *(rd++); - dst[wr_size++] = kEncTable[carry1 | (s[2] >> 6)]; - } else { - dst[wr_size++] = kEncTable[carry1]; - dst[wr_size++] = kPadding; - break; - } - - dst[wr_size++] = kEncTable[s[2] & 0x3f]; - } - PERFETTO_DCHECK(wr_size == padded_dst_size); - return static_cast(padded_dst_size); -} - -std::string Base64Encode(const void* src, size_t src_size) { - std::string dst; - dst.resize(Base64EncSize(src_size)); - auto res = Base64Encode(src, src_size, &dst[0], dst.size()); - PERFETTO_CHECK(res == static_cast(dst.size())); - return dst; -} - -ssize_t Base64Decode(const char* src, size_t src_size, uint8_t* dst, size_t dst_size) { - const size_t min_dst_size = Base64DecSize(src_size); - if (dst_size < min_dst_size) return -1; - - const char* rd = src; - const char* const end = src + src_size; - size_t wr_size = 0; - - char s[4]{}; - while (rd < end) { - uint8_t d[4]; - for (uint32_t j = 0; j < 4; j++) { - // Padding is only feasible for the last 2 chars of each group of 4. - s[j] = rd < end ? *(rd++) : (j < 2 ? '\0' : kPadding); - d[j] = DecodeChar(s[j]); - if (d[j] == kX) return -1; // Invalid input char. - } - dst[wr_size] = static_cast((d[0] << 2) | (d[1] >> 4)); - dst[wr_size + 1] = static_cast((d[1] << 4) | (d[2] >> 2)); - dst[wr_size + 2] = static_cast((d[2] << 6) | (d[3])); - wr_size += 3; - } - - PERFETTO_CHECK(wr_size <= dst_size); - wr_size -= (s[3] == kPadding ? 1 : 0) + (s[2] == kPadding ? 1 : 0); - return static_cast(wr_size); -} - -std::optional Base64Decode(const char* src, size_t src_size) { - std::string dst; - dst.resize(Base64DecSize(src_size)); - auto res = Base64Decode(src, src_size, reinterpret_cast(&dst[0]), dst.size()); - if (res < 0) return std::nullopt; // Decoding error. - - PERFETTO_CHECK(res <= static_cast(dst.size())); - dst.resize(static_cast(res)); - return std::make_optional(dst); -} - -} // namespace base -} // namespace perfetto -// gen_amalgamated begin source: src/base/crash_keys.cc -// gen_amalgamated begin header: include/perfetto/ext/base/crash_keys.h -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INCLUDE_PERFETTO_EXT_BASE_CRASH_KEYS_H_ -#define INCLUDE_PERFETTO_EXT_BASE_CRASH_KEYS_H_ - -#include -#include - -#include -#include - -// gen_amalgamated expanded: #include "perfetto/base/compiler.h" -// gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h" - -// Crash keys are very simple global variables with static-storage that -// are reported on crash time for managed crashes (CHECK/FATAL/Watchdog). -// - Translation units can define a CrashKey and register it at some point -// during initialization. -// - CrashKey instances must be long-lived. They should really be just global -// static variable in the anonymous namespace. -// Example: -// subsystem_1.cc -// CrashKey g_client_id("ipc_client_id"); -// ... -// OnIpcReceived(client_id) { -// g_client_id.Set(client_id); -// ... // Process the IPC -// g_client_id.Clear(); -// } -// Or equivalently: -// OnIpcReceived(client_id) { -// auto scoped_key = g_client_id.SetScoped(client_id); -// ... // Process the IPC -// } -// -// If a crash happens while processing the IPC, the crash report will -// have a line "ipc_client_id: 42". -// -// Thread safety considerations: -// CrashKeys can be registered and set/cleared from any thread. -// There is no compelling use-case to have full acquire/release consistency when -// setting a key. This means that if a thread crashes immediately after a -// crash key has been set on another thread, the value printed on the crash -// report could be incomplete. The code guarantees defined behavior and does -// not rely on null-terminated string (in the worst case 32 bytes of random -// garbage will be printed out). - -// The tests live in logging_unittest.cc. - -namespace perfetto { -namespace base { - -constexpr size_t kCrashKeyMaxStrSize = 32; - -// CrashKey instances must be long lived -class CrashKey { - public: - class ScopedClear { - public: - explicit ScopedClear(CrashKey* k) : key_(k) {} - ~ScopedClear() { - if (key_) key_->Clear(); - } - ScopedClear(const ScopedClear&) = delete; - ScopedClear& operator=(const ScopedClear&) = delete; - ScopedClear& operator=(ScopedClear&&) = delete; - ScopedClear(ScopedClear&& other) noexcept : key_(other.key_) { other.key_ = nullptr; } - - private: - CrashKey* key_; - }; - - // constexpr so it can be used in the anon namespace without requiring a - // global constructor. - // |name| must be a long-lived string. - constexpr explicit CrashKey(const char* name) - : registered_{}, type_(Type::kUnset), name_(name), str_value_{} {} - CrashKey(const CrashKey&) = delete; - CrashKey& operator=(const CrashKey&) = delete; - CrashKey(CrashKey&&) = delete; - CrashKey& operator=(CrashKey&&) = delete; - - enum class Type : uint8_t { kUnset = 0, kInt, kStr }; - - void Clear() { - int_value_.store(0, std::memory_order_relaxed); - type_.store(Type::kUnset, std::memory_order_relaxed); - } - - void Set(int64_t value) { - int_value_.store(value, std::memory_order_relaxed); - type_.store(Type::kInt, std::memory_order_relaxed); - if (PERFETTO_UNLIKELY(!registered_.load(std::memory_order_relaxed))) Register(); - } - - void Set(StringView sv) { - size_t len = std::min(sv.size(), sizeof(str_value_) - 1); - for (size_t i = 0; i < len; ++i) str_value_[i].store(sv.data()[i], std::memory_order_relaxed); - str_value_[len].store('\0', std::memory_order_relaxed); - type_.store(Type::kStr, std::memory_order_relaxed); - if (PERFETTO_UNLIKELY(!registered_.load(std::memory_order_relaxed))) Register(); - } - - ScopedClear SetScoped(int64_t value) PERFETTO_WARN_UNUSED_RESULT { - Set(value); - return ScopedClear(this); - } - - ScopedClear SetScoped(StringView sv) PERFETTO_WARN_UNUSED_RESULT { - Set(sv); - return ScopedClear(this); - } - - void Register(); - - int64_t int_value() const { return int_value_.load(std::memory_order_relaxed); } - size_t ToString(char* dst, size_t len); - - private: - std::atomic registered_; - std::atomic type_; - const char* const name_; - union { - std::atomic str_value_[kCrashKeyMaxStrSize]; - std::atomic int_value_; - }; -}; - -// Fills |dst| with a string containing one line for each crash key -// (excluding the unset ones). -// Returns number of chars written, without counting the NUL terminator. -// This is used in logging.cc when emitting the crash report abort message. -size_t SerializeCrashKeys(char* dst, size_t len); - -void UnregisterAllCrashKeysForTesting(); - -} // namespace base -} // namespace perfetto - -#endif // INCLUDE_PERFETTO_EXT_BASE_CRASH_KEYS_H_ -// gen_amalgamated begin header: include/perfetto/ext/base/string_utils.h -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INCLUDE_PERFETTO_EXT_BASE_STRING_UTILS_H_ -#define INCLUDE_PERFETTO_EXT_BASE_STRING_UTILS_H_ - -#include -#include -#include - -#include -#include -#include -#include - -// gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h" - -namespace perfetto { -namespace base { - -inline char Lowercase(char c) { - return ('A' <= c && c <= 'Z') ? static_cast(c - ('A' - 'a')) : c; -} - -inline char Uppercase(char c) { - return ('a' <= c && c <= 'z') ? static_cast(c + ('A' - 'a')) : c; -} - -inline std::optional CStringToUInt32(const char* s, int base = 10) { - char* endptr = nullptr; - auto value = static_cast(strtoul(s, &endptr, base)); - return (*s && !*endptr) ? std::make_optional(value) : std::nullopt; -} - -inline std::optional CStringToInt32(const char* s, int base = 10) { - char* endptr = nullptr; - auto value = static_cast(strtol(s, &endptr, base)); - return (*s && !*endptr) ? std::make_optional(value) : std::nullopt; -} - -// Note: it saturates to 7fffffffffffffff if parsing a hex number >= 0x8000... -inline std::optional CStringToInt64(const char* s, int base = 10) { - char* endptr = nullptr; - auto value = static_cast(strtoll(s, &endptr, base)); - return (*s && !*endptr) ? std::make_optional(value) : std::nullopt; -} - -inline std::optional CStringToUInt64(const char* s, int base = 10) { - char* endptr = nullptr; - auto value = static_cast(strtoull(s, &endptr, base)); - return (*s && !*endptr) ? std::make_optional(value) : std::nullopt; -} - -double StrToD(const char* nptr, char** endptr); - -inline std::optional CStringToDouble(const char* s) { - char* endptr = nullptr; - double value = StrToD(s, &endptr); - std::optional result(std::nullopt); - if (*s != '\0' && *endptr == '\0') result = value; - return result; -} - -inline std::optional StringToUInt32(const std::string& s, int base = 10) { - return CStringToUInt32(s.c_str(), base); -} - -inline std::optional StringToInt32(const std::string& s, int base = 10) { - return CStringToInt32(s.c_str(), base); -} - -inline std::optional StringToUInt64(const std::string& s, int base = 10) { - return CStringToUInt64(s.c_str(), base); -} - -inline std::optional StringToInt64(const std::string& s, int base = 10) { - return CStringToInt64(s.c_str(), base); -} - -inline std::optional StringToDouble(const std::string& s) { - return CStringToDouble(s.c_str()); -} - -bool StartsWith(const std::string& str, const std::string& prefix); -bool EndsWith(const std::string& str, const std::string& suffix); -bool StartsWithAny(const std::string& str, const std::vector& prefixes); -bool Contains(const std::string& haystack, const std::string& needle); -bool Contains(const std::string& haystack, char needle); -size_t Find(const StringView& needle, const StringView& haystack); -bool CaseInsensitiveEqual(const std::string& first, const std::string& second); -std::string Join(const std::vector& parts, const std::string& delim); -std::vector SplitString(const std::string& text, const std::string& delimiter); -std::string StripPrefix(const std::string& str, const std::string& prefix); -std::string StripSuffix(const std::string& str, const std::string& suffix); -std::string TrimWhitespace(const std::string& str); -std::string ToLower(const std::string& str); -std::string ToUpper(const std::string& str); -std::string StripChars(const std::string& str, const std::string& chars, char replacement); -std::string ToHex(const char* data, size_t size); -inline std::string ToHex(const std::string& s) { return ToHex(s.c_str(), s.size()); } -std::string IntToHexString(uint32_t number); -std::string Uint64ToHexString(uint64_t number); -std::string Uint64ToHexStringNoPrefix(uint64_t number); -std::string ReplaceAll(std::string str, const std::string& to_replace, - const std::string& replacement); - -// A BSD-style strlcpy without the return value. -// Copies at most |dst_size|-1 characters. Unlike strncpy, it always \0 -// terminates |dst|, as long as |dst_size| is not 0. -// Unlike strncpy and like strlcpy it does not zero-pad the rest of |dst|. -// Returns nothing. The BSD strlcpy returns the size of |src|, which might -// be > |dst_size|. Anecdotal experience suggests people assume the return value -// is the number of bytes written in |dst|. That assumption can lead to -// dangerous bugs. -// In order to avoid being subtly uncompliant with strlcpy AND avoid misuse, -// the choice here is to return nothing. -inline void StringCopy(char* dst, const char* src, size_t dst_size) { - for (size_t i = 0; i < dst_size; ++i) { - if ((dst[i] = src[i]) == '\0') { - return; // We hit and copied the null terminator. - } - } - - // We were left off at dst_size. We over copied 1 byte. Null terminate. - if (PERFETTO_LIKELY(dst_size > 0)) dst[dst_size - 1] = 0; -} - -// Like snprintf() but returns the number of chars *actually* written (without -// counting the null terminator) NOT "the number of chars which would have been -// written to the final string if enough space had been available". -// This should be used in almost all cases when the caller uses the return value -// of snprintf(). If the return value is not used, there is no benefit in using -// this wrapper, as this just calls snprintf() and mangles the return value. -// It always null-terminates |dst| (even in case of errors), unless -// |dst_size| == 0. -// Examples: -// SprintfTrunc(x, 4, "123whatever"): returns 3 and writes "123\0". -// SprintfTrunc(x, 4, "123"): returns 3 and writes "123\0". -// SprintfTrunc(x, 3, "123"): returns 2 and writes "12\0". -// SprintfTrunc(x, 2, "123"): returns 1 and writes "1\0". -// SprintfTrunc(x, 1, "123"): returns 0 and writes "\0". -// SprintfTrunc(x, 0, "123"): returns 0 and writes nothing. -// NOTE: This means that the caller has no way to tell when truncation happens -// vs the edge case of *just* fitting in the buffer. -size_t SprintfTrunc(char* dst, size_t dst_size, const char* fmt, ...) PERFETTO_PRINTF_FORMAT(3, 4); - -// Line number starts from 1 -struct LineWithOffset { - base::StringView line; - uint32_t line_offset; - uint32_t line_num; -}; - -// For given string and offset Pfinds a line with character for -// which offset points, what number is this line (starts from 1), and the offset -// inside this line. returns std::nullopt if the offset points to -// line break character or exceeds string length. -std::optional FindLineWithOffset(base::StringView str, uint32_t offset); - -// A helper class to facilitate construction and usage of write-once stack -// strings. -// Example usage: -// StackString<32> x("format %d %s", 42, string_arg); -// TakeString(x.c_str() | x.string_view() | x.ToStdString()); -// Rather than char x[32] + sprintf. -// Advantages: -// - Avoids useless zero-fills caused by people doing `char buf[32] {}` (mainly -// by fearing unknown snprintf failure modes). -// - Makes the code more robust in case of snprintf truncations (len() and -// string_view() will return the truncated length, unlike snprintf). -template class StackString { - public: - explicit PERFETTO_PRINTF_FORMAT(/* 1=this */ 2, 3) StackString(const char* fmt, ...) { - buf_[0] = '\0'; - va_list args; - va_start(args, fmt); - int res = vsnprintf(buf_, sizeof(buf_), fmt, args); - va_end(args); - buf_[sizeof(buf_) - 1] = '\0'; - len_ = res < 0 ? 0 : std::min(static_cast(res), sizeof(buf_) - 1); - } - - StringView string_view() const { return StringView(buf_, len_); } - std::string ToStdString() const { return std::string(buf_, len_); } - const char* c_str() const { return buf_; } - size_t len() const { return len_; } - char* mutable_data() { return buf_; } - - private: - char buf_[N]; - size_t len_ = 0; // Does not include the \0. -}; - -} // namespace base -} // namespace perfetto - -#endif // INCLUDE_PERFETTO_EXT_BASE_STRING_UTILS_H_ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// gen_amalgamated expanded: #include "perfetto/ext/base/crash_keys.h" - -#include - -#include -#include - -// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h" - -namespace perfetto { -namespace base { - -namespace { - -constexpr size_t kMaxKeys = 32; - -std::atomic g_keys[kMaxKeys]{}; -std::atomic g_num_keys{}; -} // namespace - -void CrashKey::Register() { - // If doesn't matter if we fail below. If there are no slots left, don't - // keep trying re-registering on every Set(), the outcome won't change. - - // If two threads raced on the Register(), avoid registering the key twice. - if (registered_.exchange(true)) return; - - uint32_t slot = g_num_keys.fetch_add(1); - if (slot >= kMaxKeys) { - PERFETTO_LOG("Too many crash keys registered"); - return; - } - g_keys[slot].store(this); -} - -// Returns the number of chars written, without counting the \0. -size_t CrashKey::ToString(char* dst, size_t len) { - if (len > 0) *dst = '\0'; - switch (type_.load(std::memory_order_relaxed)) { - case Type::kUnset: - break; - case Type::kInt: - return SprintfTrunc(dst, len, "%s: %" PRId64 "\n", name_, - int_value_.load(std::memory_order_relaxed)); - case Type::kStr: - char buf[sizeof(str_value_)]; - for (size_t i = 0; i < sizeof(str_value_); i++) - buf[i] = str_value_[i].load(std::memory_order_relaxed); - - // Don't assume |str_value_| is properly null-terminated. - return SprintfTrunc(dst, len, "%s: %.*s\n", name_, int(sizeof(buf)), buf); - } - return 0; -} - -void UnregisterAllCrashKeysForTesting() { - g_num_keys.store(0); - for (auto& key : g_keys) key.store(nullptr); -} - -size_t SerializeCrashKeys(char* dst, size_t len) { - size_t written = 0; - uint32_t num_keys = g_num_keys.load(); - if (len > 0) *dst = '\0'; - for (uint32_t i = 0; i < num_keys && written < len; i++) { - CrashKey* key = g_keys[i].load(); - if (!key) continue; // Can happen if we hit this between the add and the store. - written += key->ToString(dst + written, len - written); - } - PERFETTO_DCHECK(written <= len); - PERFETTO_DCHECK(len == 0 || dst[written] == '\0'); - return written; -} - -} // namespace base -} // namespace perfetto -// gen_amalgamated begin source: src/base/ctrl_c_handler.cc -// gen_amalgamated begin header: include/perfetto/ext/base/ctrl_c_handler.h -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INCLUDE_PERFETTO_EXT_BASE_CTRL_C_HANDLER_H_ -#define INCLUDE_PERFETTO_EXT_BASE_CTRL_C_HANDLER_H_ - -namespace perfetto { -namespace base { - -// On Linux/Android/Mac: installs SIGINT + SIGTERM signal handlers. -// On Windows: installs a SetConsoleCtrlHandler() handler. -// The passed handler must be async safe. -using CtrlCHandlerFunction = void (*)(); -void InstallCtrlCHandler(CtrlCHandlerFunction); - -} // namespace base -} // namespace perfetto - -#endif // INCLUDE_PERFETTO_EXT_BASE_CTRL_C_HANDLER_H_ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// gen_amalgamated expanded: #include "perfetto/ext/base/ctrl_c_handler.h" - -// gen_amalgamated expanded: #include "perfetto/base/build_config.h" -// gen_amalgamated expanded: #include "perfetto/base/compiler.h" -// gen_amalgamated expanded: #include "perfetto/base/logging.h" - -#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) -#include -#include -#else -#include -#include -#endif - -namespace perfetto { -namespace base { - -namespace { -CtrlCHandlerFunction g_handler = nullptr; -} - -void InstallCtrlCHandler(CtrlCHandlerFunction handler) { - PERFETTO_CHECK(g_handler == nullptr); - g_handler = handler; - -#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) - auto trampoline = [](DWORD type) -> int { - if (type == CTRL_C_EVENT) { - g_handler(); - return true; - } - return false; - }; - ::SetConsoleCtrlHandler(trampoline, true); -#elif PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \ - PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) - // Setup signal handler. - struct sigaction sa {}; - -// Glibc headers for sa_sigaction trigger this. -#pragma GCC diagnostic push -#if defined(__clang__) -#pragma GCC diagnostic ignored "-Wdisabled-macro-expansion" -#endif - sa.sa_handler = [](int) { g_handler(); }; - sa.sa_flags = static_cast(SA_RESETHAND | SA_RESTART); -#pragma GCC diagnostic pop - sigaction(SIGINT, &sa, nullptr); - sigaction(SIGTERM, &sa, nullptr); -#else - // Do nothing on NaCL and Fuchsia. - ignore_result(handler); -#endif -} - -} // namespace base -} // namespace perfetto -// gen_amalgamated begin source: src/base/event_fd.cc -// gen_amalgamated begin header: include/perfetto/ext/base/event_fd.h -// gen_amalgamated begin header: include/perfetto/base/platform_handle.h -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INCLUDE_PERFETTO_BASE_PLATFORM_HANDLE_H_ -#define INCLUDE_PERFETTO_BASE_PLATFORM_HANDLE_H_ - -// gen_amalgamated expanded: #include "perfetto/base/build_config.h" - -namespace perfetto { -namespace base { - -// PlatformHandle should be used only for types that are HANDLE(s) in Windows. -// It should NOT be used to blanket-replace "int fd" in the codebase. -// Windows has two types of "handles", which, in UNIX-land, both map to int: -// 1. File handles returned by the posix-compatibility API like _open(). -// These are just int(s) and should stay such, because all the posix-like API -// in Windows.h take an int, not a HANDLE. -// 2. Handles returned by old-school WINAPI like CreateFile, CreateEvent etc. -// These are proper HANDLE(s). PlatformHandle should be used here. -#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) -// Windows.h typedefs HANDLE to void*. We use void* here to avoid leaking -// Windows.h through our headers. -using PlatformHandle = void*; - -// On Windows both nullptr and 0xffff... (INVALID_HANDLE_VALUE) are invalid. -struct PlatformHandleChecker { - static inline bool IsValid(PlatformHandle h) { - return h && h != reinterpret_cast(-1); - } -}; -#else -using PlatformHandle = int; -struct PlatformHandleChecker { - static inline bool IsValid(PlatformHandle h) { return h >= 0; } -}; -#endif - -// The definition of this lives in base/file_utils.cc (to avoid creating an -// extra build edge for a one liner). This is really an alias for close() (UNIX) -// CloseHandle() (Windows). THe indirection layer is just to avoid leaking -// system headers like Windows.h through perfetto headers. -// Thre return value is always UNIX-style: 0 on success, -1 on failure. -int ClosePlatformHandle(PlatformHandle); - -} // namespace base -} // namespace perfetto - -#endif // INCLUDE_PERFETTO_BASE_PLATFORM_HANDLE_H_ -// gen_amalgamated begin header: include/perfetto/ext/base/scoped_file.h -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INCLUDE_PERFETTO_EXT_BASE_SCOPED_FILE_H_ -#define INCLUDE_PERFETTO_EXT_BASE_SCOPED_FILE_H_ - -// gen_amalgamated expanded: #include "perfetto/base/build_config.h" - -#include - -#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) -#include // For DIR* / opendir(). -#endif - -#include - -// gen_amalgamated expanded: #include "perfetto/base/export.h" -// gen_amalgamated expanded: #include "perfetto/base/logging.h" -// gen_amalgamated expanded: #include "perfetto/base/platform_handle.h" - -namespace perfetto { -namespace base { - -namespace internal { -// Used for the most common cases of ScopedResource where there is only one -// invalid value. -template struct DefaultValidityChecker { - static bool IsValid(T t) { return t != InvalidValue; } -}; -} // namespace internal - -// RAII classes for auto-releasing fds and dirs. -// if T is a pointer type, InvalidValue must be nullptr. Doing otherwise -// causes weird unexpected behaviors (See https://godbolt.org/z/5nGMW4). -template > -class ScopedResource { - public: - using ValidityChecker = Checker; - static constexpr T kInvalid = InvalidValue; - - explicit ScopedResource(T t = InvalidValue) : t_(t) {} - ScopedResource(ScopedResource&& other) noexcept { - t_ = other.t_; - other.t_ = InvalidValue; - } - ScopedResource& operator=(ScopedResource&& other) { - reset(other.t_); - other.t_ = InvalidValue; - return *this; - } - T get() const { return t_; } - T operator*() const { return t_; } - explicit operator bool() const { return Checker::IsValid(t_); } - void reset(T r = InvalidValue) { - if (Checker::IsValid(t_)) { - int res = CloseFunction(t_); - if (CheckClose) PERFETTO_CHECK(res == 0); - } - t_ = r; - } - T release() { - T t = t_; - t_ = InvalidValue; - return t; - } - ~ScopedResource() { reset(InvalidValue); } - - private: - ScopedResource(const ScopedResource&) = delete; - ScopedResource& operator=(const ScopedResource&) = delete; - T t_; -}; - -// Declared in file_utils.h. Forward declared to avoid #include cycles. -int PERFETTO_EXPORT_COMPONENT CloseFile(int fd); - -// Use this for file resources obtained via open() and similar APIs. -using ScopedFile = ScopedResource; -using ScopedFstream = ScopedResource; - -// Use this for resources that are HANDLE on Windows. See comments in -// platform_handle.h -#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) -using ScopedPlatformHandle = ScopedResource; -#else -// On non-windows systems we alias ScopedPlatformHandle to ScopedFile because -// they are really the same. This is to allow assignments between the two in -// Linux-specific code paths that predate ScopedPlatformHandle. -static_assert(std::is_same::value, ""); -using ScopedPlatformHandle = ScopedFile; - -// DIR* does not exist on Windows. -using ScopedDir = ScopedResource; -#endif - -} // namespace base -} // namespace perfetto - -#endif // INCLUDE_PERFETTO_EXT_BASE_SCOPED_FILE_H_ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INCLUDE_PERFETTO_EXT_BASE_EVENT_FD_H_ -#define INCLUDE_PERFETTO_EXT_BASE_EVENT_FD_H_ - -// gen_amalgamated expanded: #include "perfetto/base/build_config.h" -// gen_amalgamated expanded: #include "perfetto/base/platform_handle.h" -// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h" - -namespace perfetto { -namespace base { - -// A waitable event that can be used with poll/select. -// This is really a wrapper around eventfd_create with a pipe-based fallback -// for other platforms where eventfd is not supported. -class EventFd { - public: - EventFd(); - ~EventFd(); - EventFd(EventFd&&) noexcept = default; - EventFd& operator=(EventFd&&) = default; - - // The non-blocking file descriptor that can be polled to wait for the event. - PlatformHandle fd() const { return event_handle_.get(); } - - // Can be called from any thread. - void Notify(); - - // Can be called from any thread. If more Notify() are queued a Clear() call - // can clear all of them (up to 16 per call). - void Clear(); - - private: - // The eventfd, when eventfd is supported, otherwise this is the read end of - // the pipe for fallback mode. - ScopedPlatformHandle event_handle_; - -#if !PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) && !PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \ - !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) - // On Mac and other non-Linux UNIX platforms a pipe-based fallback is used. - // The write end of the wakeup pipe. - ScopedFile write_fd_; -#endif -}; - -} // namespace base -} // namespace perfetto - -#endif // INCLUDE_PERFETTO_EXT_BASE_EVENT_FD_H_ -// gen_amalgamated begin header: include/perfetto/ext/base/pipe.h -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INCLUDE_PERFETTO_EXT_BASE_PIPE_H_ -#define INCLUDE_PERFETTO_EXT_BASE_PIPE_H_ - -// gen_amalgamated expanded: #include "perfetto/base/platform_handle.h" -// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h" - -namespace perfetto { -namespace base { - -class Pipe { - public: - enum Flags { - kBothBlock = 0, -#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) - kBothNonBlock, - kRdNonBlock, - kWrNonBlock, -#endif - }; - - static Pipe Create(Flags = kBothBlock); - - Pipe(); - Pipe(Pipe&&) noexcept; - Pipe& operator=(Pipe&&); - - ScopedPlatformHandle rd; - ScopedPlatformHandle wr; -}; - -} // namespace base -} // namespace perfetto - -#endif // INCLUDE_PERFETTO_EXT_BASE_PIPE_H_ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// gen_amalgamated expanded: #include "perfetto/base/build_config.h" - -#include -#include - -#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) -#include -#include -#elif PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) -#include -#include -#else // Mac, Fuchsia and other non-Linux UNIXes -#include -#endif - -// gen_amalgamated expanded: #include "perfetto/base/logging.h" -// gen_amalgamated expanded: #include "perfetto/ext/base/event_fd.h" -// gen_amalgamated expanded: #include "perfetto/ext/base/pipe.h" -// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h" - -namespace perfetto { -namespace base { - -EventFd::~EventFd() = default; - -#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) -EventFd::EventFd() { - event_handle_.reset(CreateEventA(/*lpEventAttributes=*/nullptr, /*bManualReset=*/true, - /*bInitialState=*/false, /*bInitialState=*/nullptr)); -} - -void EventFd::Notify() { - if (!SetEvent(event_handle_.get())) // 0: fail, !0: success, unlike UNIX. - PERFETTO_DFATAL("EventFd::Notify()"); -} - -void EventFd::Clear() { - if (!ResetEvent(event_handle_.get())) // 0: fail, !0: success, unlike UNIX. - PERFETTO_DFATAL("EventFd::Clear()"); -} - -#elif PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) - -EventFd::EventFd() { - event_handle_.reset(eventfd(/*initval=*/0, EFD_CLOEXEC | EFD_NONBLOCK)); - PERFETTO_CHECK(event_handle_); -} - -void EventFd::Notify() { - const uint64_t value = 1; - ssize_t ret = write(event_handle_.get(), &value, sizeof(value)); - if (ret <= 0 && errno != EAGAIN) PERFETTO_DFATAL("EventFd::Notify()"); -} - -void EventFd::Clear() { - uint64_t value; - ssize_t ret = PERFETTO_EINTR(read(event_handle_.get(), &value, sizeof(value))); - if (ret <= 0 && errno != EAGAIN) PERFETTO_DFATAL("EventFd::Clear()"); -} - -#else - -EventFd::EventFd() { - // Make the pipe non-blocking so that we never block the waking thread (either - // the main thread or another one) when scheduling a wake-up. - Pipe pipe = Pipe::Create(Pipe::kBothNonBlock); - event_handle_ = ScopedPlatformHandle(std::move(pipe.rd).release()); - write_fd_ = std::move(pipe.wr); -} - -void EventFd::Notify() { - const uint64_t value = 1; - ssize_t ret = write(write_fd_.get(), &value, sizeof(uint8_t)); - if (ret <= 0 && errno != EAGAIN) PERFETTO_DFATAL("EventFd::Notify()"); -} - -void EventFd::Clear() { - // Drain the byte(s) written to the wake-up pipe. We can potentially read - // more than one byte if several wake-ups have been scheduled. - char buffer[16]; - ssize_t ret = PERFETTO_EINTR(read(event_handle_.get(), &buffer[0], sizeof(buffer))); - if (ret <= 0 && errno != EAGAIN) PERFETTO_DFATAL("EventFd::Clear()"); -} -#endif - -} // namespace base -} // namespace perfetto -// gen_amalgamated begin source: src/base/file_utils.cc -// gen_amalgamated begin header: include/perfetto/ext/base/file_utils.h -// gen_amalgamated begin header: include/perfetto/base/status.h -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INCLUDE_PERFETTO_BASE_STATUS_H_ -#define INCLUDE_PERFETTO_BASE_STATUS_H_ - -#include - -// gen_amalgamated expanded: #include "perfetto/base/compiler.h" -// gen_amalgamated expanded: #include "perfetto/base/export.h" -// gen_amalgamated expanded: #include "perfetto/base/logging.h" - -namespace perfetto { -namespace base { - -// Represents either the success or the failure message of a function. -// This can used as the return type of functions which would usually return an -// bool for success or int for errno but also wants to add some string context -// (ususally for logging). -class PERFETTO_EXPORT_COMPONENT Status { - public: - Status() : ok_(true) {} - explicit Status(std::string msg) : ok_(false), message_(std::move(msg)) { - PERFETTO_CHECK(!message_.empty()); - } - - // Copy operations. - Status(const Status&) = default; - Status& operator=(const Status&) = default; - - // Move operations. The moved-from state is valid but unspecified. - Status(Status&&) noexcept = default; - Status& operator=(Status&&) = default; - - bool ok() const { return ok_; } - - // When ok() is false this returns the error message. Returns the empty string - // otherwise. - const std::string& message() const { return message_; } - const char* c_message() const { return message_.c_str(); } - - private: - bool ok_ = false; - std::string message_; -}; - -// Returns a status object which represents the Ok status. -inline Status OkStatus() { return Status(); } - -PERFETTO_PRINTF_FORMAT(1, 2) Status ErrStatus(const char* format, ...); - -} // namespace base -} // namespace perfetto - -#endif // INCLUDE_PERFETTO_BASE_STATUS_H_ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INCLUDE_PERFETTO_EXT_BASE_FILE_UTILS_H_ -#define INCLUDE_PERFETTO_EXT_BASE_FILE_UTILS_H_ - -#include // For mode_t & O_RDONLY/RDWR. Exists also on Windows. -#include - -#include -#include - -// gen_amalgamated expanded: #include "perfetto/base/build_config.h" -// gen_amalgamated expanded: #include "perfetto/base/export.h" -// gen_amalgamated expanded: #include "perfetto/base/status.h" -// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h" -// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h" - -namespace perfetto { -namespace base { - -#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) -using FileOpenMode = int; -#else -using FileOpenMode = mode_t; -#endif - -constexpr FileOpenMode kFileModeInvalid = static_cast(-1); - -bool ReadPlatformHandle(PlatformHandle, std::string* out); -bool ReadFileDescriptor(int fd, std::string* out); -bool ReadFileStream(FILE* f, std::string* out); -bool ReadFile(const std::string& path, std::string* out); - -// A wrapper around read(2). It deals with Linux vs Windows includes. It also -// deals with handling EINTR. Has the same semantics of UNIX's read(2). -ssize_t Read(int fd, void* dst, size_t dst_size); - -// Call write until all data is written or an error is detected. -// -// man 2 write: -// If a write() is interrupted by a signal handler before any bytes are -// written, then the call fails with the error EINTR; if it is -// interrupted after at least one byte has been written, the call -// succeeds, and returns the number of bytes written. -ssize_t WriteAll(int fd, const void* buf, size_t count); - -ssize_t WriteAllHandle(PlatformHandle, const void* buf, size_t count); - -ScopedFile OpenFile(const std::string& path, int flags, FileOpenMode = kFileModeInvalid); -ScopedFstream OpenFstream(const char* path, const char* mode); - -// This is an alias for close(). It's to avoid leaking Windows.h in headers. -// Exported because ScopedFile is used in the /include/ext API by Chromium -// component builds. -int PERFETTO_EXPORT_COMPONENT CloseFile(int fd); - -bool FlushFile(int fd); - -// Returns true if mkdir succeeds, false if it fails (see errno in that case). -bool Mkdir(const std::string& path); - -// Calls rmdir() on UNIX, _rmdir() on Windows. -bool Rmdir(const std::string& path); - -// Wrapper around access(path, F_OK). -bool FileExists(const std::string& path); - -// Gets the extension for a filename. If the file has two extensions, returns -// only the last one (foo.pb.gz => .gz). Returns empty string if there is no -// extension. -std::string GetFileExtension(const std::string& filename); - -// Puts the path to all files under |dir_path| in |output|, recursively walking -// subdirectories. File paths are relative to |dir_path|. Only files are -// included, not directories. Path separator is always '/', even on windows (not -// '\'). -base::Status ListFilesRecursive(const std::string& dir_path, std::vector& output); - -} // namespace base -} // namespace perfetto - -#endif // INCLUDE_PERFETTO_EXT_BASE_FILE_UTILS_H_ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// gen_amalgamated expanded: #include "perfetto/ext/base/file_utils.h" - -#include -#include - -#include -#include -#include -#include -#include - -// gen_amalgamated expanded: #include "perfetto/base/build_config.h" -// gen_amalgamated expanded: #include "perfetto/base/logging.h" -// gen_amalgamated expanded: #include "perfetto/base/platform_handle.h" -// gen_amalgamated expanded: #include "perfetto/base/status.h" -// gen_amalgamated expanded: #include "perfetto/ext/base/platform.h" -// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h" -// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h" - -#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) -#include -#include -#include -#include -#else -#include -#include -#endif - -namespace perfetto { -namespace base { -namespace { -constexpr size_t kBufSize = 2048; - -#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) -// Wrap FindClose to: (1) make the return unix-style; (2) deal with stdcall. -int CloseFindHandle(HANDLE h) { return FindClose(h) ? 0 : -1; } - -std::optional ToUtf16(const std::string str) { - int len = MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast(str.size()), nullptr, 0); - if (len < 0) { - return std::nullopt; - } - std::vector tmp; - tmp.resize(static_cast::size_type>(len)); - len = MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast(str.size()), tmp.data(), - static_cast(tmp.size())); - if (len < 0) { - return std::nullopt; - } - PERFETTO_CHECK(static_cast::size_type>(len) == tmp.size()); - return std::wstring(tmp.data(), tmp.size()); -} - -#endif - -} // namespace - -ssize_t Read(int fd, void* dst, size_t dst_size) { - ssize_t ret; - platform::BeforeMaybeBlockingSyscall(); -#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) - ret = _read(fd, dst, static_cast(dst_size)); -#else - ret = PERFETTO_EINTR(read(fd, dst, dst_size)); -#endif - platform::AfterMaybeBlockingSyscall(); - return ret; -} - -bool ReadFileDescriptor(int fd, std::string* out) { - // Do not override existing data in string. - size_t i = out->size(); - - struct stat buf {}; - if (fstat(fd, &buf) != -1) { - if (buf.st_size > 0) out->resize(i + static_cast(buf.st_size)); - } - - ssize_t bytes_read; - for (;;) { - if (out->size() < i + kBufSize) out->resize(out->size() + kBufSize); - - bytes_read = Read(fd, &((*out)[i]), kBufSize); - if (bytes_read > 0) { - i += static_cast(bytes_read); - } else { - out->resize(i); - return bytes_read == 0; - } - } -} - -bool ReadPlatformHandle(PlatformHandle h, std::string* out) { -#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) - // Do not override existing data in string. - size_t i = out->size(); - - for (;;) { - if (out->size() < i + kBufSize) out->resize(out->size() + kBufSize); - DWORD bytes_read = 0; - auto res = ::ReadFile(h, &((*out)[i]), kBufSize, &bytes_read, nullptr); - if (res && bytes_read > 0) { - i += static_cast(bytes_read); - } else { - out->resize(i); - const bool is_eof = res && bytes_read == 0; - auto err = res ? 0 : GetLastError(); - // The "Broken pipe" error on Windows is slighly different than Unix: - // On Unix: a "broken pipe" error can happen only on the writer side. On - // the reader there is no broken pipe, just a EOF. - // On windows: the reader also sees a broken pipe error. - // Here we normalize on the Unix behavior, treating broken pipe as EOF. - return is_eof || err == ERROR_BROKEN_PIPE; - } - } -#else - return ReadFileDescriptor(h, out); -#endif -} - -bool ReadFileStream(FILE* f, std::string* out) { return ReadFileDescriptor(fileno(f), out); } - -bool ReadFile(const std::string& path, std::string* out) { - base::ScopedFile fd = base::OpenFile(path, O_RDONLY); - if (!fd) return false; - - return ReadFileDescriptor(*fd, out); -} - -ssize_t WriteAll(int fd, const void* buf, size_t count) { - size_t written = 0; - while (written < count) { - // write() on windows takes an unsigned int size. - uint32_t bytes_left = - static_cast(std::min(count - written, static_cast(UINT32_MAX))); - platform::BeforeMaybeBlockingSyscall(); - ssize_t wr = PERFETTO_EINTR(write(fd, static_cast(buf) + written, bytes_left)); - platform::AfterMaybeBlockingSyscall(); - if (wr == 0) break; - if (wr < 0) return wr; - written += static_cast(wr); - } - return static_cast(written); -} - -ssize_t WriteAllHandle(PlatformHandle h, const void* buf, size_t count) { -#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) - DWORD wsize = 0; - if (::WriteFile(h, buf, static_cast(count), &wsize, nullptr)) { - return wsize; - } else { - return -1; - } -#else - return WriteAll(h, buf, count); -#endif -} - -bool FlushFile(int fd) { - PERFETTO_DCHECK(fd != 0); -#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) - return !PERFETTO_EINTR(fdatasync(fd)); -#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) - return !PERFETTO_EINTR(_commit(fd)); -#else - return !PERFETTO_EINTR(fsync(fd)); -#endif -} - -bool Mkdir(const std::string& path) { -#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) - return _mkdir(path.c_str()) == 0; -#else - return mkdir(path.c_str(), 0755) == 0; -#endif -} - -bool Rmdir(const std::string& path) { -#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) - return _rmdir(path.c_str()) == 0; -#else - return rmdir(path.c_str()) == 0; -#endif -} - -int CloseFile(int fd) { return close(fd); } - -ScopedFile OpenFile(const std::string& path, int flags, FileOpenMode mode) { - // If a new file might be created, ensure that the permissions for the new - // file are explicitly specified. - PERFETTO_CHECK((flags & O_CREAT) == 0 || mode != kFileModeInvalid); -#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) - // Always use O_BINARY on Windows, to avoid silly EOL translations. - ScopedFile fd(_open(path.c_str(), flags | O_BINARY, mode)); -#else - // Always open a ScopedFile with O_CLOEXEC so we can safely fork and exec. - ScopedFile fd(open(path.c_str(), flags | O_CLOEXEC, mode)); -#endif - return fd; -} - -ScopedFstream OpenFstream(const char* path, const char* mode) { - ScopedFstream file; -// On Windows fopen interprets filename using the ANSI or OEM codepage but -// sqlite3_value_text returns a UTF-8 string. To make sure we interpret the -// filename correctly we use _wfopen and a UTF-16 string on windows. -#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) - auto w_path = ToUtf16(path); - auto w_mode = ToUtf16(mode); - if (w_path && w_mode) { - file.reset(_wfopen(w_path->c_str(), w_mode->c_str())); - } -#else - file.reset(fopen(path, mode)); -#endif - return file; -} - -bool FileExists(const std::string& path) { -#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) - return _access(path.c_str(), 0) == 0; -#else - return access(path.c_str(), F_OK) == 0; -#endif -} - -// Declared in base/platform_handle.h. -int ClosePlatformHandle(PlatformHandle handle) { -#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) - // Make the return value UNIX-style. - return CloseHandle(handle) ? 0 : -1; -#else - return close(handle); -#endif -} - -base::Status ListFilesRecursive(const std::string& dir_path, std::vector& output) { - std::string root_dir_path = dir_path; - if (root_dir_path.back() == '\\') { - root_dir_path.back() = '/'; - } else if (root_dir_path.back() != '/') { - root_dir_path.push_back('/'); - } - - // dir_queue contains full paths to the directories. The paths include the - // root_dir_path at the beginning and the trailing slash at the end. - std::deque dir_queue; - dir_queue.push_back(root_dir_path); - - while (!dir_queue.empty()) { - const std::string cur_dir = std::move(dir_queue.front()); - dir_queue.pop_front(); -#if PERFETTO_BUILDFLAG(PERFETTO_OS_NACL) - return base::ErrStatus("ListFilesRecursive not supported yet"); -#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) - std::string glob_path = cur_dir + "*"; - // + 1 because we also have to count the NULL terminator. - if (glob_path.length() + 1 > MAX_PATH) - return base::ErrStatus("Directory path %s is too long", dir_path.c_str()); - WIN32_FIND_DATAA ffd; - - base::ScopedResource - hFind(FindFirstFileA(glob_path.c_str(), &ffd)); - if (!hFind) { - // For empty directories, there should be at least one entry '.'. - // If FindFirstFileA returns INVALID_HANDLE_VALUE, this means directory - // couldn't be accessed. - return base::ErrStatus("Failed to open directory %s", cur_dir.c_str()); - } - do { - if (strcmp(ffd.cFileName, ".") == 0 || strcmp(ffd.cFileName, "..") == 0) continue; - if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - std::string subdir_path = cur_dir + ffd.cFileName + '/'; - dir_queue.push_back(subdir_path); - } else { - const std::string full_path = cur_dir + ffd.cFileName; - PERFETTO_CHECK(full_path.length() > root_dir_path.length()); - output.push_back(full_path.substr(root_dir_path.length())); - } - } while (FindNextFileA(*hFind, &ffd)); -#else - ScopedDir dir = ScopedDir(opendir(cur_dir.c_str())); - if (!dir) { - return base::ErrStatus("Failed to open directory %s", cur_dir.c_str()); - } - for (auto* dirent = readdir(dir.get()); dirent != nullptr; dirent = readdir(dir.get())) { - if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) { - continue; - } - if (dirent->d_type == DT_DIR) { - dir_queue.push_back(cur_dir + dirent->d_name + '/'); - } else if (dirent->d_type == DT_REG) { - const std::string full_path = cur_dir + dirent->d_name; - PERFETTO_CHECK(full_path.length() > root_dir_path.length()); - output.push_back(full_path.substr(root_dir_path.length())); - } - } -#endif - } - return base::OkStatus(); -} - -std::string GetFileExtension(const std::string& filename) { - auto ext_idx = filename.rfind('.'); - if (ext_idx == std::string::npos) return std::string(); - return filename.substr(ext_idx); -} - -} // namespace base -} // namespace perfetto -// gen_amalgamated begin source: src/base/getopt_compat.cc -// gen_amalgamated begin header: include/perfetto/ext/base/getopt_compat.h -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INCLUDE_PERFETTO_EXT_BASE_GETOPT_COMPAT_H_ -#define INCLUDE_PERFETTO_EXT_BASE_GETOPT_COMPAT_H_ - -#include // For std::nullptr_t - -// No translation units other than base/getopt.h and getopt_compat_unittest.cc -// should directly include this file. Use base/getopt.h instead. - -namespace perfetto { -namespace base { -namespace getopt_compat { - -// A tiny getopt() replacement for Windows, which doesn't have . -// This implementation is based on the subset of features that we use in the -// Perfetto codebase. It doesn't even try to deal with the full surface of GNU's -// getopt(). -// Limitations: -// - getopt_long_only() is not supported. -// - optional_argument is not supported. That is extremely subtle and caused us -// problems in the past with GNU's getopt. -// - It does not reorder non-option arguments. It behaves like MacOS getopt, or -// GNU's when POSIXLY_CORRECT=1. -// - Doesn't expose optopt or opterr. -// - option.flag and longindex are not supported and must be nullptr. - -enum { - no_argument = 0, - required_argument = 1, -}; - -struct option { - const char* name; - int has_arg; - std::nullptr_t flag; // Only nullptr is supported. - int val; -}; - -extern char* optarg; -extern int optind; -extern int optopt; -extern int opterr; - -int getopt_long(int argc, char** argv, const char* shortopts, const option* longopts, - std::nullptr_t /*longindex is not supported*/); - -int getopt(int argc, char** argv, const char* shortopts); - -} // namespace getopt_compat -} // namespace base -} // namespace perfetto - -#endif // INCLUDE_PERFETTO_EXT_BASE_GETOPT_COMPAT_H_ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// gen_amalgamated expanded: #include "perfetto/ext/base/getopt_compat.h" - -#include -#include -#include - -#include - -// gen_amalgamated expanded: #include "perfetto/base/logging.h" - -namespace perfetto { -namespace base { -namespace getopt_compat { - -char* optarg = nullptr; -int optind = 0; -int optopt = 0; -int opterr = 1; - -namespace { - -char* nextchar = nullptr; - -const option* LookupLongOpt(const std::vector