SWDEV-419012: Adding New Perfetto SDK & Fixing early destruction of perfetto plugin

Change-Id: Ie1d8e753f10a1ba0686b021c14b788b444499f14


[ROCm/rocprofiler commit: 5d1320928c]
Tento commit je obsažen v:
Ammar ELWazir
2024-05-08 01:47:31 -05:00
odevzdal Ammar Elwazir
rodič ac46f39b22
revize f93fad8364
12 změnil soubory, kde provedl 218 přidání a 219808 odebrání
+6
Zobrazit soubor
@@ -0,0 +1,6 @@
[submodule "perfetto"]
path = plugin/perfetto/perfetto
url = https://github.com/google/perfetto.git
branch = releases/v44.x
+149
Zobrazit soubor
@@ -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()
+12 -4
Zobrazit soubor
@@ -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
Submodul projects/rocprofiler/plugin/perfetto/perfetto přidán v eb5ef24c58
+44 -54
Zobrazit soubor
@@ -45,7 +45,7 @@
#include <sys/types.h>
#include <unistd.h>
#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<TrackID>
};
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<perfetto::TracingSession> tracing_session_;
fs::path output_prefix_;
int file_descriptor_;
bool is_valid_{false};
size_t roctx_track_entries_{0};
std::atomic<bool> internal_buffer_finished{false};
// Correlate stream id(s) with correlation id(s) to identify the stream id of every HIP activity
std::unordered_map<uint64_t, uint64_t> 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<std::mutex> lock(writing_lock);
// std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> lock(writing_lock);
if (!perfetto_plugin || !perfetto_plugin->IsValid()) return -1;
return perfetto_plugin->FlushTracerRecord(record, rocprofiler_session_id_t{0});
}
-8
Zobrazit soubor
@@ -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 $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/sdk>)
-189
Zobrazit soubor
@@ -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.
-35
Zobrazit soubor
@@ -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
@@ -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 <perfetto.h>
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.h>
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<CustomDataSource> {
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<perfetto::TracingSession> 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<char> 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
Rozdílový obsah nebyl zobrazen, protože je příliš veliký Načíst rozdílové porovnání
Rozdílový obsah nebyl zobrazen, protože je příliš veliký Načíst rozdílové porovnání
+6 -3
Zobrazit soubor
@@ -153,7 +153,7 @@ class rocprofiler_plugin_t {
decltype(rocprofiler_plugin_write_record)* rocprofiler_plugin_write_record_;
};
std::optional<rocprofiler_plugin_t> plugin;
rocprofiler_plugin_t* plugin;
struct hsa_api_trace_entry_t {
std::atomic<uint32_t> valid;
@@ -436,6 +436,8 @@ void finish() {
rocprofiler::TraceBufferBase::FlushAll();
CHECK_ROCPROFILER(rocprofiler_terminate_session(session_id));
}
// delete plugin;
// If hsa_shut_down() is not called from the application then we may still have async calls back
// to the rocprofiler to use session parameters, thats why we need to leak the session up till
// this is fixed in the ROCR-Runtime
@@ -506,8 +508,9 @@ void plugins_load(void* userdata) {
.plugin_path = fs::path(dl_info.dli_fname).replace_filename(plugin_name),
.userdata = userdata
};
if (!plugin.emplace(header).is_valid()) {
plugin.reset();
plugin = new rocprofiler_plugin_t{header};
if (!plugin->is_valid()) {
delete plugin;
}
}
}