mirror of
https://github.com/elwrcl/intel-hard-graphics.git
synced 2026-10-31 19:08:03 +03:00
init
This commit is contained in:
12511 files changed
+6156641
No files matched your search
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright © 2021 Google LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
int dlclose(void *handle)
|
||||
{
|
||||
/* do nothing */
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# Copyright © 2021 Google LLC
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
shared_library('dlclose-skip',
|
||||
'dlclose-skip.c',
|
||||
install : true,
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# Copyright © 2021 Collabora, Ltd.
|
||||
# Author: Antonio Caggiano <[email protected]>
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
if with_perfetto and dep_libdrm.found()
|
||||
subdir('pps')
|
||||
endif
|
||||
|
||||
if with_tools.contains('dlclose-skip')
|
||||
subdir('dlclose-skip')
|
||||
endif
|
||||
@@ -0,0 +1,21 @@
|
||||
BasedOnStyle: WebKit
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Linux
|
||||
ColumnLimit: 100
|
||||
Cpp11BracedListStyle: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
NamespaceIndentation: None
|
||||
PointerAlignment: Right
|
||||
SortIncludes: CaseSensitive
|
||||
SpaceAfterTemplateKeyword: false
|
||||
Standard: c++11
|
||||
TabWidth: 3
|
||||
IndentWidth: 3
|
||||
ConstructorInitializerIndentWidth: 3
|
||||
ContinuationIndentWidth: 3
|
||||
@@ -0,0 +1,25 @@
|
||||
buffers {
|
||||
size_kb: 16384
|
||||
fill_policy: RING_BUFFER
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "gpu.renderstages.amd"
|
||||
}
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "track_event"
|
||||
track_event_config {
|
||||
enabled_categories: "mesa.default"
|
||||
enabled_categories: "mesa.slow"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
duration_ms: 2000
|
||||
write_into_file: true
|
||||
file_write_period_ms: 500
|
||||
flush_period_ms: 500
|
||||
@@ -0,0 +1,33 @@
|
||||
buffers {
|
||||
size_kb: 1024
|
||||
fill_policy: RING_BUFFER
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "gpu.counters.i915"
|
||||
gpu_counter_config {
|
||||
counter_period_ns: 1000000000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "gpu.counters.panfrost"
|
||||
gpu_counter_config {
|
||||
counter_period_ns: 1000000000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "gpu.counters.v3d"
|
||||
gpu_counter_config {
|
||||
counter_period_ns: 100000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
duration_ms: 16000
|
||||
@@ -0,0 +1,74 @@
|
||||
buffers {
|
||||
size_kb: 16384
|
||||
fill_policy: RING_BUFFER
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "linux.ftrace"
|
||||
target_buffer: 0
|
||||
ftrace_config {
|
||||
buffer_size_kb: 65536
|
||||
drain_period_ms: 1000
|
||||
|
||||
ftrace_events: "scm/scm_call_start"
|
||||
ftrace_events: "scm/scm_call_end"
|
||||
ftrace_events: "drm/drm_vblank_event"
|
||||
ftrace_events: "dma_fence/dma_fence_destroy"
|
||||
ftrace_events: "dma_fence/dma_fence_enable_signal"
|
||||
ftrace_events: "dma_fence/dma_fence_signaled"
|
||||
ftrace_events: "dma_fence/dma_fence_wait_start"
|
||||
ftrace_events: "dma_fence/dma_fence_emit"
|
||||
ftrace_events: "dma_fence/dma_fence_init"
|
||||
ftrace_events: "dma_fence/dma_fence_wait_end"
|
||||
ftrace_events: "cpufreq_interactive_already"
|
||||
ftrace_events: "cpufreq_interactive_boost"
|
||||
ftrace_events: "cpufreq_interactive_notyet"
|
||||
ftrace_events: "cpufreq_interactive_setspeed"
|
||||
ftrace_events: "cpufreq_interactive_target"
|
||||
ftrace_events: "cpufreq_interactive_unboost"
|
||||
ftrace_events: "sched_blocked_reason"
|
||||
ftrace_events: "sched_cpu_hotplug"
|
||||
ftrace_events: "sched_process_exec"
|
||||
ftrace_events: "sched_process_exit"
|
||||
ftrace_events: "sched_process_fork"
|
||||
ftrace_events: "sched_process_free"
|
||||
ftrace_events: "sched_process_hang"
|
||||
ftrace_events: "sched_process_wait"
|
||||
ftrace_events: "sched_switch"
|
||||
ftrace_events: "sched_wakeup_new"
|
||||
ftrace_events: "sched_wakeup"
|
||||
ftrace_events: "sched_waking"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "gpu.counters.i915"
|
||||
gpu_counter_config {
|
||||
counter_period_ns: 100000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "gpu.renderstages.intel"
|
||||
}
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "track_event"
|
||||
track_event_config {
|
||||
enabled_categories: "mesa.default"
|
||||
enabled_categories: "mesa.slow"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
duration_ms: 1200
|
||||
write_into_file: true
|
||||
file_write_period_ms: 500
|
||||
flush_period_ms: 500
|
||||
@@ -0,0 +1,74 @@
|
||||
buffers {
|
||||
size_kb: 16384
|
||||
fill_policy: RING_BUFFER
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "linux.ftrace"
|
||||
target_buffer: 0
|
||||
ftrace_config {
|
||||
buffer_size_kb: 65536
|
||||
drain_period_ms: 1000
|
||||
|
||||
ftrace_events: "scm/scm_call_start"
|
||||
ftrace_events: "scm/scm_call_end"
|
||||
ftrace_events: "drm/drm_vblank_event"
|
||||
ftrace_events: "dma_fence/dma_fence_destroy"
|
||||
ftrace_events: "dma_fence/dma_fence_enable_signal"
|
||||
ftrace_events: "dma_fence/dma_fence_signaled"
|
||||
ftrace_events: "dma_fence/dma_fence_wait_start"
|
||||
ftrace_events: "dma_fence/dma_fence_emit"
|
||||
ftrace_events: "dma_fence/dma_fence_init"
|
||||
ftrace_events: "dma_fence/dma_fence_wait_end"
|
||||
ftrace_events: "cpufreq_interactive_already"
|
||||
ftrace_events: "cpufreq_interactive_boost"
|
||||
ftrace_events: "cpufreq_interactive_notyet"
|
||||
ftrace_events: "cpufreq_interactive_setspeed"
|
||||
ftrace_events: "cpufreq_interactive_target"
|
||||
ftrace_events: "cpufreq_interactive_unboost"
|
||||
ftrace_events: "sched_blocked_reason"
|
||||
ftrace_events: "sched_cpu_hotplug"
|
||||
ftrace_events: "sched_process_exec"
|
||||
ftrace_events: "sched_process_exit"
|
||||
ftrace_events: "sched_process_fork"
|
||||
ftrace_events: "sched_process_free"
|
||||
ftrace_events: "sched_process_hang"
|
||||
ftrace_events: "sched_process_wait"
|
||||
ftrace_events: "sched_switch"
|
||||
ftrace_events: "sched_wakeup_new"
|
||||
ftrace_events: "sched_wakeup"
|
||||
ftrace_events: "sched_waking"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "gpu.counters.xe"
|
||||
gpu_counter_config {
|
||||
counter_period_ns: 100000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "gpu.renderstages.intel"
|
||||
}
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "track_event"
|
||||
track_event_config {
|
||||
enabled_categories: "mesa.default"
|
||||
enabled_categories: "mesa.slow"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
duration_ms: 1200
|
||||
write_into_file: true
|
||||
file_write_period_ms: 500
|
||||
flush_period_ms: 500
|
||||
@@ -0,0 +1,185 @@
|
||||
# Enable periodic flushing of the trace buffer into the output file.
|
||||
write_into_file: true
|
||||
|
||||
# Writes the userspace buffer into the file every .5 seconds.
|
||||
file_write_period_ms: 500
|
||||
|
||||
# Commits the trace from the shared memory buffer to the central buffer
|
||||
# periodically. Otherwise, the --full-sort option will be required for
|
||||
# trace_processor_shell and traceconv when importing the trace.
|
||||
flush_period_ms: 2000
|
||||
|
||||
duration_ms: 7000
|
||||
|
||||
buffers {
|
||||
size_kb: 65536
|
||||
fill_policy: DISCARD
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "gpu.counters.msm"
|
||||
gpu_counter_config {
|
||||
counter_period_ns: 100000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "gpu.renderstages.msm"
|
||||
}
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "gpu.memory.msm"
|
||||
}
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "gpu.counters.i915"
|
||||
gpu_counter_config {
|
||||
counter_period_ns: 100000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "gpu.renderstages.intel"
|
||||
}
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "gpu.renderstages.amd"
|
||||
}
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "gpu.renderstages.panfrost"
|
||||
}
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "gpu.counters.panfrost"
|
||||
gpu_counter_config {
|
||||
counter_period_ns: 100000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "gpu.counters.v3d"
|
||||
gpu_counter_config {
|
||||
counter_period_ns: 100000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "track_event"
|
||||
track_event_config {
|
||||
#enabled_tags: "slow"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "linux.ftrace"
|
||||
target_buffer: 0
|
||||
ftrace_config {
|
||||
buffer_size_kb: 16384
|
||||
drain_period_ms: 500
|
||||
|
||||
ftrace_events: "scm/scm_call_start"
|
||||
ftrace_events: "scm/scm_call_end"
|
||||
ftrace_events: "drm/drm_vblank_event"
|
||||
ftrace_events: "dma_fence/dma_fence_destroy"
|
||||
ftrace_events: "dma_fence/dma_fence_enable_signal"
|
||||
ftrace_events: "dma_fence/dma_fence_signaled"
|
||||
ftrace_events: "dma_fence/dma_fence_wait_start"
|
||||
ftrace_events: "dma_fence/dma_fence_emit"
|
||||
ftrace_events: "dma_fence/dma_fence_init"
|
||||
ftrace_events: "dma_fence/dma_fence_wait_end"
|
||||
ftrace_events: "gpu_mem/gpu_mem_total"
|
||||
ftrace_events: "clock_disable"
|
||||
ftrace_events: "clock_enable"
|
||||
ftrace_events: "clock_set_rate"
|
||||
ftrace_events: "power/cpu_frequency_limits"
|
||||
ftrace_events: "power/cpu_frequency"
|
||||
ftrace_events: "power/cpu_idle"
|
||||
ftrace_events: "raw_syscalls/sys_enter"
|
||||
ftrace_events: "raw_syscalls/sys_exit"
|
||||
ftrace_events: "cpufreq_interactive_already"
|
||||
ftrace_events: "cpufreq_interactive_boost"
|
||||
ftrace_events: "cpufreq_interactive_notyet"
|
||||
ftrace_events: "cpufreq_interactive_setspeed"
|
||||
ftrace_events: "cpufreq_interactive_target"
|
||||
ftrace_events: "cpufreq_interactive_unboost"
|
||||
ftrace_events: "sched_blocked_reason"
|
||||
ftrace_events: "sched_cpu_hotplug"
|
||||
ftrace_events: "sched_process_exec"
|
||||
ftrace_events: "sched_process_exit"
|
||||
ftrace_events: "sched_process_fork"
|
||||
ftrace_events: "sched_process_free"
|
||||
ftrace_events: "sched_process_hang"
|
||||
ftrace_events: "sched_process_wait"
|
||||
ftrace_events: "sched_switch"
|
||||
ftrace_events: "sched_wakeup_new"
|
||||
ftrace_events: "sched_wakeup"
|
||||
ftrace_events: "sched_waking"
|
||||
ftrace_events: "smbus_read"
|
||||
ftrace_events: "smbus_reply"
|
||||
ftrace_events: "smbus_result"
|
||||
ftrace_events: "smbus_write"
|
||||
ftrace_events: "softirq_entry"
|
||||
ftrace_events: "softirq_exit"
|
||||
ftrace_events: "softirq_raise"
|
||||
ftrace_events: "suspend_resume"
|
||||
ftrace_events: "workqueue_activate_work"
|
||||
ftrace_events: "workqueue_execute_end"
|
||||
ftrace_events: "workqueue_execute_start"
|
||||
ftrace_events: "workqueue_queue_work"
|
||||
ftrace_events: "signal_generate"
|
||||
ftrace_events: "signal_deliver"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "linux.process_stats"
|
||||
target_buffer: 0
|
||||
}
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "track_event"
|
||||
track_event_config {
|
||||
enabled_categories: "mesa.default"
|
||||
enabled_categories: "mesa.slow"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data_sources {
|
||||
config {
|
||||
name: "perfetto.metatrace"
|
||||
target_buffer: 0
|
||||
}
|
||||
}
|
||||
|
||||
producers {
|
||||
producer_name: "perfetto.traced_probes"
|
||||
shm_size_kb: 4096
|
||||
page_size_kb: 4
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
# Copyright © 2020-2021 Collabora, Ltd.
|
||||
# Author: Antonio Caggiano <[email protected]>
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
pps_sources = [
|
||||
'pps.cc',
|
||||
'pps_device.cc',
|
||||
'pps_driver.cc',
|
||||
'pps_counter.cc',
|
||||
]
|
||||
|
||||
include_pps = include_directories('../')
|
||||
|
||||
dep_drm = dependency('libdrm')
|
||||
|
||||
pps_deps = [
|
||||
dep_drm,
|
||||
dep_perfetto,
|
||||
idep_mesautil,
|
||||
pps_datasources,
|
||||
]
|
||||
|
||||
lib_pps = static_library(
|
||||
'pps',
|
||||
sources: pps_sources,
|
||||
include_directories: [include_pps, inc_src, inc_util, pps_includes],
|
||||
dependencies: pps_deps,
|
||||
)
|
||||
|
||||
dep_pps = declare_dependency(
|
||||
link_with: lib_pps,
|
||||
include_directories: [include_pps, inc_src]
|
||||
)
|
||||
|
||||
producer_sources = [
|
||||
'pps_datasource.cc',
|
||||
'pps_producer.cc'
|
||||
]
|
||||
|
||||
executable(
|
||||
'pps-producer',
|
||||
sources: producer_sources,
|
||||
include_directories: [include_pps, inc_src],
|
||||
dependencies: [dep_pps, dep_perfetto],
|
||||
install: true
|
||||
)
|
||||
|
||||
if with_platform_android
|
||||
shared_library(
|
||||
'gpudataproducer',
|
||||
sources: producer_sources,
|
||||
include_directories: [include_pps, inc_src],
|
||||
dependencies: [dep_pps, dep_perfetto],
|
||||
install: true
|
||||
)
|
||||
endif
|
||||
|
||||
config_sources = [
|
||||
'pps_config.cc'
|
||||
]
|
||||
|
||||
dep_docopt = dependency('docopt', required: false)
|
||||
|
||||
if dep_docopt.found()
|
||||
executable(
|
||||
'pps-config',
|
||||
sources: config_sources,
|
||||
include_directories: [include_pps, inc_src],
|
||||
dependencies: [dep_pps, dep_docopt],
|
||||
install: true
|
||||
)
|
||||
endif
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright © 2020 Collabora, Ltd.
|
||||
* Author: Antonio Caggiano <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "pps.h"
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
|
||||
#include <sched.h>
|
||||
|
||||
namespace pps
|
||||
{
|
||||
bool check(int res, const char *msg)
|
||||
{
|
||||
if (res < 0) {
|
||||
char *err_msg = std::strerror(errno);
|
||||
PERFETTO_ELOG("%s: %s", msg, err_msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void make_thread_rt()
|
||||
{
|
||||
// Use FIFO policy to avoid preemption while collecting counters
|
||||
int sched_policy = SCHED_FIFO;
|
||||
// Do not use max priority to avoid starving migration and watchdog threads
|
||||
int priority_value = sched_get_priority_max(sched_policy) - 1;
|
||||
sched_param priority_param { priority_value };
|
||||
sched_setscheduler(0, sched_policy, &priority_param);
|
||||
}
|
||||
|
||||
} // namespace pps
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright © 2020 Collabora, Ltd.
|
||||
* Author: Antonio Caggiano <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef ANDROID_LIBPERFETTO
|
||||
#include <perfetto.h>
|
||||
#else
|
||||
#include <perfetto/tracing.h>
|
||||
#include <perfetto/common/gpu_counter_descriptor.gen.h>
|
||||
#include <perfetto/common/gpu_counter_descriptor.pbzero.h>
|
||||
#include <perfetto/config/gpu/gpu_counter_config.pbzero.h>
|
||||
#include <perfetto/trace/clock_snapshot.pbzero.h>
|
||||
#include <perfetto/trace/gpu/gpu_counter_event.pbzero.h>
|
||||
#endif
|
||||
|
||||
#define PPS_LOG PERFETTO_LOG
|
||||
#define PPS_LOG_IMPORTANT PERFETTO_ILOG
|
||||
#define PPS_LOG_ERROR PERFETTO_ELOG
|
||||
#define PPS_LOG_FATAL PERFETTO_FATAL
|
||||
|
||||
namespace pps
|
||||
{
|
||||
enum class State {
|
||||
Stop, // initial state, or stopped by the tracing service
|
||||
Start, // running, sampling data
|
||||
};
|
||||
|
||||
/// @brief Checks whether a return value is valid
|
||||
/// @param res Result from a syscall
|
||||
/// @param msg Message to prepend to strerror
|
||||
/// @return True if ok, false otherwise
|
||||
bool check(int res, const char *msg);
|
||||
|
||||
void make_thread_rt();
|
||||
|
||||
/// @param num Numerator
|
||||
/// @param den Denominator
|
||||
/// @return A ratio between two floating point numbers, or 0 if the denominator is 0
|
||||
constexpr double ratio(double num, double den)
|
||||
{
|
||||
return den > 0.0 ? num / den : 0.0;
|
||||
}
|
||||
|
||||
} // namespace pps
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright © 2020 Collabora, Ltd.
|
||||
* Author: Antonio Caggiano <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#define FIND_IF(c, lambda) (std::find_if(std::begin(c), std::end(c), lambda))
|
||||
#define FIND(c, e) (std::find(std::begin(c), std::end(c), e))
|
||||
#define CONTAINS(c, e) (FIND(c, e) != std::end(c))
|
||||
#define CONTAINS_IT(c, it) (it != std::end(c))
|
||||
#define APPEND(a, b) (a.insert(std::end(a), std::begin(b), std::end(b)))
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright © 2020-2021 Collabora, Ltd.
|
||||
* Author: Antonio Caggiano <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <pps/pps_driver.h>
|
||||
|
||||
#include <charconv>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
#include <thread>
|
||||
|
||||
#include <docopt/docopt.h>
|
||||
|
||||
static const char *USAGE =
|
||||
R"(pps-config
|
||||
|
||||
Usage:
|
||||
pps-config info
|
||||
pps-config dump [--gpu=<n>] [--ids=<n>] [--sec=<n>]
|
||||
pps-config groups [--gpu=<n>]
|
||||
pps-config counters [--gpu=<n>]
|
||||
pps-config (-h | --help)
|
||||
pps-config --version
|
||||
|
||||
Options:
|
||||
-h --help Show this screen.
|
||||
--version Show version.
|
||||
--gpu=<n> GPU number to query [default: 0].
|
||||
--ids=<n> Comma separated list of numbers.
|
||||
--sec=<n> Seconds to wait before dumping performance counters [default: 1].
|
||||
)";
|
||||
|
||||
// Tool running mode
|
||||
enum class Mode {
|
||||
// Show help message
|
||||
Help,
|
||||
|
||||
// Show system information
|
||||
Info,
|
||||
|
||||
// Show list of available counters
|
||||
Counters,
|
||||
|
||||
// Groups
|
||||
Groups,
|
||||
|
||||
// Dump performance counters
|
||||
Dump,
|
||||
};
|
||||
|
||||
std::vector<std::string_view> split(const std::string &list, const std::string &separator)
|
||||
{
|
||||
std::vector<std::string_view> ret;
|
||||
std::string_view list_view = list;
|
||||
while (!list_view.empty()) {
|
||||
size_t pos = list_view.find(separator);
|
||||
if (pos == std::string::npos) {
|
||||
ret.push_back(list_view);
|
||||
break;
|
||||
}
|
||||
ret.push_back(list_view.substr(0, pos));
|
||||
list_view = list_view.substr(pos + separator.length(), list_view.length());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::optional<uint32_t> to_counter_id(const std::string_view &view)
|
||||
{
|
||||
uint32_t counter_id = 0;
|
||||
|
||||
auto res = std::from_chars(view.data(), view.data() + view.size(), counter_id);
|
||||
if (res.ec == std::errc::invalid_argument) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return counter_id;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
using namespace pps;
|
||||
|
||||
Mode mode = Mode::Help;
|
||||
auto secs = std::chrono::seconds(1);
|
||||
uint32_t gpu_num = 0;
|
||||
std::vector<uint32_t> counter_ids;
|
||||
|
||||
auto args =
|
||||
docopt::docopt(USAGE, {std::next(argv), std::next(argv, argc)}, true, "pps-config 0.3");
|
||||
|
||||
if (args["info"].asBool()) {
|
||||
mode = Mode::Info;
|
||||
}
|
||||
|
||||
if (args["dump"].asBool()) {
|
||||
mode = Mode::Dump;
|
||||
}
|
||||
|
||||
if (args["--gpu"]) {
|
||||
gpu_num = static_cast<uint32_t>(args["--gpu"].asLong());
|
||||
}
|
||||
|
||||
if (args["--ids"]) {
|
||||
auto comma_separated_list = args["--ids"].asString();
|
||||
std::vector<std::string_view> ids_list = split(comma_separated_list, ",");
|
||||
|
||||
for (auto &id : ids_list) {
|
||||
if (auto counter_id = to_counter_id(id)) {
|
||||
counter_ids.push_back(*counter_id);
|
||||
} else {
|
||||
fprintf(stderr, "Failed to parse counter ids: %s\n", comma_separated_list.c_str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (args["--sec"]) {
|
||||
secs = std::chrono::seconds(args["--sec"].asLong());
|
||||
}
|
||||
|
||||
if (args["groups"].asBool()) {
|
||||
mode = Mode::Groups;
|
||||
}
|
||||
|
||||
if (args["counters"].asBool()) {
|
||||
mode = Mode::Counters;
|
||||
}
|
||||
|
||||
// Docopt shows the help message for us
|
||||
if (mode == Mode::Help) {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
default:
|
||||
break;
|
||||
case Mode::Info: {
|
||||
// Header: device name, and whether it is supported or not
|
||||
printf("#%4s %16s %16s\n", "num", "device", "support");
|
||||
|
||||
auto devices = DrmDevice::create_all();
|
||||
for (auto &device : devices) {
|
||||
auto gpu_num = device.gpu_num;
|
||||
auto name = device.name;
|
||||
auto driver = Driver::get_driver(std::move(device));
|
||||
printf(" %4u %16s %16s\n", gpu_num, name.c_str(), driver ? "yes" : "no");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case Mode::Dump: {
|
||||
if (auto device = DrmDevice::create(gpu_num)) {
|
||||
if (auto driver = Driver::get_driver(std::move(device.value()))) {
|
||||
driver->init_perfcnt();
|
||||
|
||||
// Enable counters
|
||||
if (counter_ids.empty()) {
|
||||
driver->enable_all_counters();
|
||||
} else {
|
||||
for (auto id : counter_ids) {
|
||||
driver->enable_counter(id);
|
||||
}
|
||||
}
|
||||
|
||||
driver->enable_perfcnt(std::chrono::nanoseconds(secs).count());
|
||||
std::this_thread::sleep_for(std::chrono::seconds(secs));
|
||||
|
||||
// Try dumping until it succeeds
|
||||
while (!driver->dump_perfcnt())
|
||||
;
|
||||
// Try collecting samples until it succeeds
|
||||
while (!driver->next())
|
||||
;
|
||||
|
||||
printf("#%32s %32s\n", "counter", "value");
|
||||
for (auto &counter : driver->enabled_counters) {
|
||||
printf(" %32s ", counter.name.c_str());
|
||||
auto value = counter.get_value(*driver);
|
||||
if (auto d_val = std::get_if<double>(&value)) {
|
||||
printf("%32f\n", *d_val);
|
||||
} else if (auto i_val = std::get_if<int64_t>(&value))
|
||||
printf("%32li\n", *i_val);
|
||||
else {
|
||||
printf("%32s\n", "error");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Mode::Groups: {
|
||||
if (auto device = DrmDevice::create(gpu_num)) {
|
||||
if (auto driver = Driver::get_driver(std::move(device.value()))) {
|
||||
driver->init_perfcnt();
|
||||
printf("#%4s %32s\n", "id", "name");
|
||||
|
||||
for (auto &group : driver->groups) {
|
||||
printf(" %4u %32s\n", group.id, group.name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case Mode::Counters: {
|
||||
if (auto device = DrmDevice::create(gpu_num)) {
|
||||
if (auto driver = Driver::get_driver(std::move(device.value()))) {
|
||||
driver->init_perfcnt();
|
||||
printf("#%4s %32s\n", "id", "name");
|
||||
|
||||
for (uint32_t i = 0; i < driver->counters.size(); ++i) {
|
||||
auto &counter = driver->counters[i];
|
||||
printf(" %4u %32s\n", counter.id, counter.name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} // switch
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright © 2019-2020 Collabora, Ltd.
|
||||
* Author: Antonio Caggiano <[email protected]>
|
||||
* Author: Rohan Garg <[email protected]>
|
||||
* Author: Robert Beckett <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "pps_counter.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#include "pps_algorithm.h"
|
||||
|
||||
namespace pps
|
||||
{
|
||||
Counter::Counter(int32_t id, const std::string &name, int32_t group)
|
||||
: id {id}
|
||||
, name {name}
|
||||
, group {group}
|
||||
{
|
||||
assert(id >= 0 && "Invalid counter ID");
|
||||
assert(group >= 0 && "Invalid group ID");
|
||||
}
|
||||
|
||||
bool Counter::operator==(const Counter &other) const
|
||||
{
|
||||
return id == other.id;
|
||||
}
|
||||
|
||||
} // namespace pps
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright © 2020 Collabora, Ltd.
|
||||
* Author: Antonio Caggiano <[email protected]>
|
||||
* Author: Rohan Garg <[email protected]>
|
||||
* Author: Robert Beckett <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
namespace pps
|
||||
{
|
||||
struct CounterGroup {
|
||||
std::string name;
|
||||
|
||||
uint32_t id;
|
||||
|
||||
/// List of counters ID belonging to this group
|
||||
std::vector<int32_t> counters;
|
||||
|
||||
std::vector<CounterGroup> subgroups;
|
||||
};
|
||||
|
||||
class Driver;
|
||||
|
||||
class Counter
|
||||
{
|
||||
public:
|
||||
/// @brief A counter value can be of different types depending on what it represents:
|
||||
/// cycles, cycles-per-instruction, percentages, bytes, and so on.
|
||||
enum class Units {
|
||||
Percent,
|
||||
Byte,
|
||||
Hertz,
|
||||
None,
|
||||
};
|
||||
|
||||
using Value = std::variant<int64_t, double>;
|
||||
|
||||
/// @param c Counter which we want to retrieve a value
|
||||
/// @param d Driver used to sample performance counters
|
||||
/// @return The value of the counter
|
||||
using Getter = Value(const Counter &c, const Driver &d);
|
||||
|
||||
Counter() = default;
|
||||
virtual ~Counter() = default;
|
||||
|
||||
/// @param id ID of the counter
|
||||
/// @param name Name of the counter
|
||||
/// @param group Group ID this counter belongs to
|
||||
Counter(int32_t id, const std::string &name, int32_t group);
|
||||
|
||||
bool operator==(const Counter &c) const;
|
||||
|
||||
/// @param get New getter function for this counter
|
||||
void set_getter(const std::function<Getter> &get);
|
||||
|
||||
/// @brief d Driver used to sample performance counters
|
||||
/// @return Last sampled value for this counter
|
||||
Value get_value(const Driver &d) const;
|
||||
|
||||
/// Id of the counter
|
||||
int32_t id = -1;
|
||||
|
||||
/// Name of the counter
|
||||
std::string name = "";
|
||||
|
||||
/// Description of the counter
|
||||
std::string description = "";
|
||||
|
||||
/// ID of the group this counter belongs to
|
||||
int32_t group = -1;
|
||||
|
||||
/// Offset of this counter within GPU counter list
|
||||
/// For derived counters it is negative and remains unused
|
||||
int32_t offset = -1;
|
||||
|
||||
/// Whether it is a derived counter or not
|
||||
bool derived = false;
|
||||
|
||||
/// Returns the value of this counter
|
||||
std::function<Getter> getter;
|
||||
|
||||
/// The unit of the counter
|
||||
Units units;
|
||||
};
|
||||
|
||||
/// @param get New getter function for this counter
|
||||
inline void Counter::set_getter(const std::function<Getter> &get)
|
||||
{
|
||||
getter = get;
|
||||
}
|
||||
|
||||
/// @brief d Driver used to sample performance counters
|
||||
/// @return Last sampled value for this counter
|
||||
inline Counter::Value Counter::get_value(const Driver &d) const
|
||||
{
|
||||
return getter(*this, d);
|
||||
}
|
||||
|
||||
/// @return The underlying u32 value
|
||||
template<typename T> constexpr uint32_t to_u32(T &&elem)
|
||||
{
|
||||
return static_cast<uint32_t>(elem);
|
||||
}
|
||||
|
||||
} // namespace pps
|
||||
@@ -0,0 +1,402 @@
|
||||
/*
|
||||
* Copyright © 2019-2021 Collabora, Ltd.
|
||||
* Author: Antonio Caggiano <[email protected]>
|
||||
* Author: Rohan Garg <[email protected]>
|
||||
* Author: Robert Beckett <[email protected]>
|
||||
* Author: Corentin Noël <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "util/detect_os.h"
|
||||
#include "pps_datasource.h"
|
||||
#include "pps_driver.h"
|
||||
|
||||
#include <condition_variable>
|
||||
#include <thread>
|
||||
#include <variant>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Minimum supported sampling period in nanoseconds
|
||||
#define MIN_SAMPLING_PERIOD_NS 5000
|
||||
|
||||
namespace pps
|
||||
{
|
||||
/// A data source supports one driver at a time, but if you need more
|
||||
/// than one gpu datasource you can just run another producer
|
||||
static Driver *driver = nullptr;
|
||||
|
||||
/// Synchronize access to started_cv and started
|
||||
static std::mutex started_m;
|
||||
static std::condition_variable started_cv;
|
||||
static bool started = false;
|
||||
|
||||
float ms(const std::chrono::nanoseconds &t)
|
||||
{
|
||||
return t.count() / 1000000.0f;
|
||||
}
|
||||
|
||||
void GpuDataSource::OnSetup(const SetupArgs &args)
|
||||
{
|
||||
if (!driver->init_perfcnt())
|
||||
PPS_LOG_ERROR("Failed to initialize %s driver", driver->drm_device.name.c_str());
|
||||
|
||||
// Parse perfetto config
|
||||
const std::string &config_raw = args.config->gpu_counter_config_raw();
|
||||
perfetto::protos::pbzero::GpuCounterConfig::Decoder config(config_raw);
|
||||
|
||||
if (config.has_counter_ids()) {
|
||||
// Get enabled counters
|
||||
PPS_LOG_IMPORTANT("Selecting counters");
|
||||
for (auto it = config.counter_ids(); it; ++it) {
|
||||
uint32_t counter_id = it->as_uint32();
|
||||
driver->enable_counter(counter_id);
|
||||
}
|
||||
} else {
|
||||
// Enable all counters
|
||||
driver->enable_all_counters();
|
||||
}
|
||||
|
||||
// Get sampling period
|
||||
auto min_sampling_period = std::chrono::nanoseconds(MIN_SAMPLING_PERIOD_NS);
|
||||
|
||||
auto dev_supported = std::chrono::nanoseconds(driver->get_min_sampling_period_ns());
|
||||
if (dev_supported > min_sampling_period) {
|
||||
min_sampling_period = dev_supported;
|
||||
}
|
||||
|
||||
time_to_sleep = std::max(time_to_sleep, min_sampling_period);
|
||||
|
||||
if (config.has_counter_period_ns()) {
|
||||
auto requested_sampling_period = std::chrono::nanoseconds(config.counter_period_ns());
|
||||
if (requested_sampling_period < min_sampling_period) {
|
||||
PPS_LOG_ERROR("Sampling period should be greater than %" PRIu64 " ns (%.2f ms)",
|
||||
uint64_t(min_sampling_period.count()),
|
||||
ms(min_sampling_period));
|
||||
} else {
|
||||
time_to_sleep = requested_sampling_period;
|
||||
}
|
||||
}
|
||||
PPS_LOG("Sampling period set to %" PRIu64 " ns", uint64_t(time_to_sleep.count()));
|
||||
}
|
||||
|
||||
void GpuDataSource::OnStart(const StartArgs &args)
|
||||
{
|
||||
driver->enable_perfcnt(time_to_sleep.count());
|
||||
|
||||
state = State::Start;
|
||||
got_first_counters = false;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(started_m);
|
||||
started = true;
|
||||
}
|
||||
started_cv.notify_all();
|
||||
}
|
||||
|
||||
void close_callback(GpuDataSource::TraceContext ctx)
|
||||
{
|
||||
auto packet = ctx.NewTracePacket();
|
||||
packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
|
||||
packet->set_timestamp(perfetto::base::GetBootTimeNs().count());
|
||||
packet->Finalize();
|
||||
ctx.Flush();
|
||||
PPS_LOG("Context flushed");
|
||||
}
|
||||
|
||||
void GpuDataSource::OnStop(const StopArgs &args)
|
||||
{
|
||||
state = State::Stop;
|
||||
auto stop_closure = args.HandleStopAsynchronously();
|
||||
Trace(close_callback);
|
||||
stop_closure();
|
||||
|
||||
driver->disable_perfcnt();
|
||||
|
||||
std::lock_guard<std::mutex> lock(started_m);
|
||||
started = false;
|
||||
}
|
||||
|
||||
void GpuDataSource::wait_started()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(started_m);
|
||||
if (!started) {
|
||||
PPS_LOG("Waiting for start");
|
||||
started_cv.wait(lock, [] { return started; });
|
||||
}
|
||||
}
|
||||
|
||||
template <typename GpuCounterDescriptor> void add_group(GpuCounterDescriptor *desc,
|
||||
const CounterGroup &group,
|
||||
const std::string &prefix,
|
||||
int32_t gpu_num)
|
||||
{
|
||||
if (!group.counters.empty()) {
|
||||
// Define a block for each group containing counters
|
||||
auto block_desc = desc->add_blocks();
|
||||
block_desc->set_name(prefix + "." + group.name);
|
||||
block_desc->set_block_id(group.id);
|
||||
|
||||
// Associate counters to blocks
|
||||
for (auto id : group.counters) {
|
||||
block_desc->add_counter_ids(id);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const &sub : group.subgroups) {
|
||||
// Perfetto doesnt currently support nested groups.
|
||||
// Flatten group hierarchy, using dot separator
|
||||
add_group(desc, sub, prefix + "." + group.name, gpu_num);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename GpuCounterDescriptor> void add_descriptors(GpuCounterDescriptor *desc,
|
||||
std::vector<CounterGroup> const &groups,
|
||||
std::vector<Counter> const &counters,
|
||||
Driver &driver)
|
||||
{
|
||||
// Add the groups
|
||||
for (auto const &group : groups) {
|
||||
add_group(desc, group, driver.drm_device.name, driver.drm_device.gpu_num);
|
||||
}
|
||||
|
||||
// Add the counters
|
||||
for (auto const &counter : counters) {
|
||||
auto spec = desc->add_specs();
|
||||
spec->set_counter_id(counter.id);
|
||||
spec->set_name(counter.name);
|
||||
spec->set_description(counter.description);
|
||||
|
||||
auto units = GpuCounterDescriptor::NONE;
|
||||
switch (counter.units) {
|
||||
case Counter::Units::Percent:
|
||||
units = GpuCounterDescriptor::PERCENT;
|
||||
break;
|
||||
case Counter::Units::Byte:
|
||||
units = GpuCounterDescriptor::BYTE;
|
||||
break;
|
||||
case Counter::Units::Hertz:
|
||||
units = GpuCounterDescriptor::HERTZ;
|
||||
break;
|
||||
case Counter::Units::None:
|
||||
units = GpuCounterDescriptor::NONE;
|
||||
break;
|
||||
default:
|
||||
assert(false && "Missing counter units type!");
|
||||
break;
|
||||
}
|
||||
spec->add_numerator_units(units);
|
||||
spec->set_select_by_default(true);
|
||||
}
|
||||
}
|
||||
|
||||
void add_samples(perfetto::protos::pbzero::GpuCounterEvent &event, const Driver &driver,
|
||||
std::unordered_map<uint32_t, double>& last_counter_vals)
|
||||
{
|
||||
if (driver.enabled_counters.size() == 0) {
|
||||
PPS_LOG_FATAL("There are no counters enabled");
|
||||
}
|
||||
|
||||
for (const auto &counter : driver.enabled_counters) {
|
||||
auto it = last_counter_vals.find(counter.id);
|
||||
auto value = counter.get_value(driver);
|
||||
if (auto d_value = std::get_if<double>(&value)) {
|
||||
if (it != last_counter_vals.end() && it->second == 0 && *d_value == 0)
|
||||
continue;
|
||||
auto counter_event = event.add_counters();
|
||||
counter_event->set_counter_id(counter.id);
|
||||
counter_event->set_double_value(*d_value);
|
||||
last_counter_vals[counter.id] = *d_value;
|
||||
} else if (auto i_value = std::get_if<int64_t>(&value)) {
|
||||
if (it != last_counter_vals.end() && it->second == 0 && *i_value == 0)
|
||||
continue;
|
||||
auto counter_event = event.add_counters();
|
||||
counter_event->set_counter_id(counter.id);
|
||||
counter_event->set_int_value(*i_value);
|
||||
last_counter_vals[counter.id] = static_cast<double>(*i_value);
|
||||
} else {
|
||||
PPS_LOG_ERROR("Failed to get value for counter %s", counter.name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add_timestamp(perfetto::protos::pbzero::ClockSnapshot *event, const Driver *driver)
|
||||
{
|
||||
uint32_t gpu_clock_id = driver->gpu_clock_id();
|
||||
if (perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME == gpu_clock_id)
|
||||
return;
|
||||
|
||||
// Send a correlation event between GPU & CPU timestamps
|
||||
uint64_t cpu_ts, gpu_ts;
|
||||
|
||||
// Try to use the optimized driver correlation if available, otherwise do a
|
||||
// separate CPU & GPU sample
|
||||
if (!driver->cpu_gpu_timestamp(cpu_ts, gpu_ts)) {
|
||||
cpu_ts = perfetto::base::GetBootTimeNs().count();
|
||||
gpu_ts = driver->gpu_timestamp();
|
||||
}
|
||||
|
||||
{
|
||||
auto clock = event->add_clocks();
|
||||
|
||||
clock->set_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
|
||||
clock->set_timestamp(cpu_ts);
|
||||
}
|
||||
|
||||
{
|
||||
auto clock = event->add_clocks();
|
||||
|
||||
clock->set_clock_id(gpu_clock_id);
|
||||
clock->set_timestamp(gpu_ts);
|
||||
}
|
||||
}
|
||||
|
||||
void GpuDataSource::trace(TraceContext &ctx)
|
||||
{
|
||||
using namespace perfetto::protos::pbzero;
|
||||
|
||||
auto state = ctx.GetIncrementalState();
|
||||
|
||||
if (state->was_cleared) {
|
||||
descriptor_timestamp = perfetto::base::GetBootTimeNs().count();
|
||||
|
||||
{
|
||||
// Mark any incremental state before this point invalid
|
||||
auto packet = ctx.NewTracePacket();
|
||||
packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
|
||||
packet->set_timestamp(descriptor_timestamp);
|
||||
packet->set_sequence_flags(TracePacket::SEQ_INCREMENTAL_STATE_CLEARED);
|
||||
}
|
||||
|
||||
descriptor_timestamp = perfetto::base::GetBootTimeNs().count();
|
||||
{
|
||||
// Counter descriptions
|
||||
auto packet = ctx.NewTracePacket();
|
||||
auto event = packet->set_gpu_counter_event();
|
||||
event->set_gpu_id(driver->drm_device.gpu_num);
|
||||
|
||||
// Start a counter descriptor
|
||||
auto desc = event->set_counter_descriptor();
|
||||
auto &groups = driver->groups;
|
||||
auto &counters = driver->enabled_counters;
|
||||
add_descriptors(desc, groups, counters, *driver);
|
||||
}
|
||||
|
||||
{
|
||||
// Initial timestamp correlation event
|
||||
auto packet = ctx.NewTracePacket();
|
||||
packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
|
||||
packet->set_timestamp(descriptor_timestamp);
|
||||
auto event = packet->set_clock_snapshot();
|
||||
add_timestamp(event, driver);
|
||||
}
|
||||
|
||||
// Capture GPU timestamp of the first packet. Anything prior to this can
|
||||
// be discarded.
|
||||
descriptor_gpu_timestamp = driver->gpu_timestamp();
|
||||
state->was_cleared = false;
|
||||
state->last_counter_vals.clear();
|
||||
}
|
||||
|
||||
if (driver->dump_perfcnt()) {
|
||||
while (auto gpu_timestamp = driver->next()) {
|
||||
if (gpu_timestamp <= descriptor_gpu_timestamp) {
|
||||
// Do not send counter values before counter descriptors
|
||||
PPS_LOG_ERROR("Skipping counter values coming before descriptors");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!got_first_counters) {
|
||||
PPS_LOG("Got first counters at gpu_ts=0x%016" PRIx64, gpu_timestamp);
|
||||
got_first_counters = true;
|
||||
}
|
||||
|
||||
auto packet = ctx.NewTracePacket();
|
||||
packet->set_timestamp_clock_id(driver->gpu_clock_id());
|
||||
packet->set_timestamp(gpu_timestamp);
|
||||
|
||||
auto event = packet->set_gpu_counter_event();
|
||||
event->set_gpu_id(driver->drm_device.gpu_num);
|
||||
|
||||
add_samples(*event, *driver, state->last_counter_vals);
|
||||
|
||||
samples_since_correlation++;
|
||||
}
|
||||
}
|
||||
|
||||
if (samples_since_correlation > 3) {
|
||||
auto packet = ctx.NewTracePacket();
|
||||
packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
|
||||
packet->set_timestamp(perfetto::base::GetBootTimeNs().count());
|
||||
auto event = packet->set_clock_snapshot();
|
||||
add_timestamp(event, driver);
|
||||
samples_since_correlation = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void GpuDataSource::trace_callback(TraceContext ctx)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
nanoseconds sleep_time = nanoseconds(0);
|
||||
|
||||
if (auto data_source = ctx.GetDataSourceLocked()) {
|
||||
if (data_source->time_to_sleep > data_source->time_to_trace) {
|
||||
sleep_time = data_source->time_to_sleep - data_source->time_to_trace;
|
||||
}
|
||||
}
|
||||
|
||||
// Wait sampling period before tracing
|
||||
std::this_thread::sleep_for(sleep_time);
|
||||
|
||||
auto time_zero = perfetto::base::GetBootTimeNs();
|
||||
if (auto data_source = ctx.GetDataSourceLocked()) {
|
||||
// Check data source is still running
|
||||
if (data_source->state == pps::State::Start) {
|
||||
data_source->trace(ctx);
|
||||
data_source->time_to_trace = perfetto::base::GetBootTimeNs() - time_zero;
|
||||
}
|
||||
} else {
|
||||
PPS_LOG("Tracing finished");
|
||||
}
|
||||
}
|
||||
|
||||
void GpuDataSource::register_data_source(const std::string &driver_name)
|
||||
{
|
||||
// Create drivers for all supported devices
|
||||
auto drm_devices = DrmDevice::create_all();
|
||||
for (auto &drm_device : drm_devices) {
|
||||
if (drm_device.name != driver_name)
|
||||
continue;
|
||||
|
||||
if (auto _driver = Driver::get_driver(std::move(drm_device))) {
|
||||
if (!_driver->init_perfcnt()) {
|
||||
// Skip failing driver
|
||||
PPS_LOG_ERROR("Failed to initialize %s driver", _driver->drm_device.name.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
driver = _driver;
|
||||
}
|
||||
}
|
||||
if (driver == nullptr) {
|
||||
PPS_LOG_FATAL("No DRM devices supported");
|
||||
}
|
||||
|
||||
static perfetto::DataSourceDescriptor dsd;
|
||||
#if DETECT_OS_ANDROID
|
||||
// Android tooling expects this data source name
|
||||
dsd.set_name("gpu.counters");
|
||||
#else
|
||||
dsd.set_name("gpu.counters." + driver_name);
|
||||
#endif
|
||||
// Start a counter descriptor
|
||||
perfetto::protos::gen::GpuCounterDescriptor desc;
|
||||
auto &groups = driver->groups;
|
||||
auto &counters = driver->counters;
|
||||
add_descriptors(&desc, groups, counters, *driver);
|
||||
dsd.set_gpu_counter_descriptor_raw(desc.SerializeAsString());
|
||||
Register(dsd);
|
||||
}
|
||||
|
||||
} // namespace pps
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright © 2019-2021 Collabora, Ltd.
|
||||
* Author: Antonio Caggiano <[email protected]>
|
||||
* Author: Robert Beckett <[email protected]>
|
||||
* Author: Corentin Noël <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pps.h"
|
||||
#include "pps_driver.h"
|
||||
|
||||
namespace pps
|
||||
{
|
||||
struct GpuIncrementalState {
|
||||
bool was_cleared = true;
|
||||
std::unordered_map<uint32_t, double> last_counter_vals;
|
||||
};
|
||||
|
||||
struct GpuDataSourceTraits : public perfetto::DefaultDataSourceTraits {
|
||||
using IncrementalStateType = GpuIncrementalState;
|
||||
};
|
||||
|
||||
class Driver;
|
||||
|
||||
/// @brief This datasource samples performance counters at a specified rate.
|
||||
/// Once the data is available, it sends a protobuf packet to the perfetto service.
|
||||
/// At the very beginning, it sends a description of the counters.
|
||||
/// After that, it sends counter values using the IDs set in the description.
|
||||
class GpuDataSource : public perfetto::DataSource<GpuDataSource, GpuDataSourceTraits>
|
||||
{
|
||||
public:
|
||||
void OnSetup(const SetupArgs &args) override;
|
||||
void OnStart(const StartArgs &args) override;
|
||||
void OnStop(const StopArgs &args) override;
|
||||
|
||||
/// Blocks until the data source starts
|
||||
static void wait_started();
|
||||
|
||||
/// @brief Perfetto trace callback
|
||||
static void trace_callback(TraceContext ctx);
|
||||
static void register_data_source(const std::string &driver_name);
|
||||
|
||||
void trace(TraceContext &ctx);
|
||||
|
||||
private:
|
||||
State state = State::Stop;
|
||||
|
||||
/// Time between trace callbacks
|
||||
std::chrono::nanoseconds time_to_sleep = std::chrono::nanoseconds(1000000);
|
||||
|
||||
/// Used to check whether the datasource is quick enough
|
||||
std::chrono::nanoseconds time_to_trace;
|
||||
|
||||
/// Last CPU timestamp at which we correlated CPU/GPU timestamps
|
||||
unsigned samples_since_correlation = 0;
|
||||
|
||||
/// CPU timestamp of packet sent with counter descriptors
|
||||
uint64_t descriptor_timestamp = 0;
|
||||
|
||||
/// GPU timestamp of packet sent with counter descriptors
|
||||
uint64_t descriptor_gpu_timestamp = 0;
|
||||
|
||||
/// Used to track the first available counters
|
||||
bool got_first_counters = false;
|
||||
};
|
||||
|
||||
} // namespace pps
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright © 2020 Collabora, Ltd.
|
||||
* Author: Antonio Caggiano <[email protected]>
|
||||
* Author: Rohan Garg <[email protected]>
|
||||
* Author: Robert Beckett <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "pps_device.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <fcntl.h>
|
||||
#include <memory>
|
||||
#include <unistd.h>
|
||||
#include <xf86drm.h>
|
||||
|
||||
#include "util/os_misc.h"
|
||||
|
||||
namespace pps
|
||||
{
|
||||
#define MAX_DRM_DEVICES 64
|
||||
|
||||
uint32_t DrmDevice::device_count()
|
||||
{
|
||||
drmDevicePtr devices[MAX_DRM_DEVICES] = {};
|
||||
int num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES);
|
||||
drmFreeDevices(devices, num_devices);
|
||||
return static_cast<uint32_t>(num_devices);
|
||||
}
|
||||
|
||||
/// @return The name of a DRM device, empty string in case of error
|
||||
std::string query_drm_name(const int fd)
|
||||
{
|
||||
assert(fd && "Failed to query DrmDevice: invalid fd");
|
||||
|
||||
std::string name = "";
|
||||
|
||||
if (drmVersionPtr version = drmGetVersion(fd)) {
|
||||
name = std::string(version->name, version->name_len);
|
||||
drmFreeVersion(version);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/// @return A DRM device, nullopt in case of error
|
||||
std::optional<DrmDevice> create_drm_device(int fd, int32_t gpu_num)
|
||||
{
|
||||
if (fd < 0 || gpu_num < 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Try getting the name
|
||||
std::string name = query_drm_name(fd);
|
||||
if (name.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const char *dri_prime = os_get_option("DRI_PRIME");
|
||||
if (dri_prime != NULL) {
|
||||
drmDevicePtr drm_device;
|
||||
uint16_t vendor_id, device_id;
|
||||
bool prime_is_vid_did =
|
||||
sscanf(dri_prime, "%hx:%hx", &vendor_id, &device_id) == 2;
|
||||
|
||||
if (prime_is_vid_did && drmGetDevice2(fd, 0, &drm_device) == 0) {
|
||||
if (drm_device->bustype == DRM_BUS_PCI &&
|
||||
(drm_device->deviceinfo.pci->vendor_id != vendor_id ||
|
||||
drm_device->deviceinfo.pci->device_id != device_id))
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
auto ret = DrmDevice();
|
||||
ret.fd = fd;
|
||||
ret.gpu_num = gpu_num;
|
||||
ret.name = name;
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<DrmDevice> DrmDevice::create_all()
|
||||
{
|
||||
std::vector<DrmDevice> ret = {};
|
||||
|
||||
drmDevicePtr devices[MAX_DRM_DEVICES] = {};
|
||||
int num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES);
|
||||
if (num_devices <= 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (int32_t gpu_num = 0; gpu_num < num_devices; gpu_num++) {
|
||||
drmDevicePtr device = devices[gpu_num];
|
||||
if ((device->available_nodes & (1 << DRM_NODE_RENDER))) {
|
||||
int fd = open(device->nodes[DRM_NODE_RENDER], O_RDWR);
|
||||
|
||||
// If it can create a device, push it into the vector
|
||||
if (auto drm_device = create_drm_device(fd, gpu_num)) {
|
||||
ret.emplace_back(std::move(drm_device.value()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drmFreeDevices(devices, num_devices);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::optional<DrmDevice> DrmDevice::create(int32_t gpu_num)
|
||||
{
|
||||
std::optional<DrmDevice> ret = std::nullopt;
|
||||
|
||||
if (gpu_num < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
drmDevicePtr devices[MAX_DRM_DEVICES] = {};
|
||||
int num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES);
|
||||
|
||||
if (num_devices > 0 && gpu_num < num_devices) {
|
||||
drmDevicePtr device = devices[gpu_num];
|
||||
int fd = open(device->nodes[DRM_NODE_RENDER], O_RDWR);
|
||||
ret = create_drm_device(fd, gpu_num);
|
||||
}
|
||||
|
||||
drmFreeDevices(devices, num_devices);
|
||||
return ret;
|
||||
}
|
||||
|
||||
DrmDevice::DrmDevice(DrmDevice &&other)
|
||||
: fd {other.fd}
|
||||
, gpu_num {other.gpu_num}
|
||||
, name {std::move(other.name)}
|
||||
{
|
||||
other.fd = -1;
|
||||
other.gpu_num = -1;
|
||||
}
|
||||
|
||||
DrmDevice &DrmDevice::operator=(DrmDevice &&other)
|
||||
{
|
||||
std::swap(fd, other.fd);
|
||||
std::swap(gpu_num, other.gpu_num);
|
||||
std::swap(name, other.name);
|
||||
return *this;
|
||||
}
|
||||
|
||||
DrmDevice::~DrmDevice()
|
||||
{
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
DrmDevice::operator bool() const
|
||||
{
|
||||
return !name.empty();
|
||||
}
|
||||
|
||||
} // namespace pps
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright © 2020 Collabora, Ltd.
|
||||
* Author: Antonio Caggiano <[email protected]>
|
||||
* Author: Rohan Garg <[email protected]>
|
||||
* Author: Robert Beckett <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace pps
|
||||
{
|
||||
/// @brief Helper class for a DRM device
|
||||
class DrmDevice
|
||||
{
|
||||
public:
|
||||
/// @return The number of DRM devices available in the system
|
||||
static uint32_t device_count();
|
||||
|
||||
/// @return All DRM devices available in the system
|
||||
static std::vector<DrmDevice> create_all();
|
||||
|
||||
/// @return A DRM device selected by its number in the system, nullopt otherwise
|
||||
static std::optional<DrmDevice> create(int32_t gpu_num);
|
||||
|
||||
/// @brief Prefer calling create instead of default constructor
|
||||
DrmDevice() = default;
|
||||
|
||||
// Allow move
|
||||
DrmDevice(DrmDevice &&);
|
||||
DrmDevice &operator=(DrmDevice &&);
|
||||
|
||||
// Forbid copy
|
||||
DrmDevice(const DrmDevice &) = delete;
|
||||
DrmDevice &operator=(const DrmDevice &) = delete;
|
||||
|
||||
~DrmDevice();
|
||||
|
||||
/// @return Whether a device has a valid name
|
||||
operator bool() const;
|
||||
|
||||
/// File descriptor of the device opened in read/write mode
|
||||
int fd = -1;
|
||||
int32_t gpu_num = -1;
|
||||
std::string name = "";
|
||||
};
|
||||
|
||||
} // namespace pps
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright © 2019-2020 Collabora, Ltd.
|
||||
* Author: Antonio Caggiano <[email protected]>
|
||||
* Author: Rohan Garg <[email protected]>
|
||||
* Author: Robert Beckett <[email protected]>
|
||||
* Author: Corentin Noël <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "pps_driver.h"
|
||||
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
|
||||
#ifdef PPS_FREEDRENO
|
||||
#include "freedreno/ds/fd_pps_driver.h"
|
||||
#endif // PPS_FREEDRENO
|
||||
|
||||
#ifdef PPS_INTEL
|
||||
#include "intel/ds/intel_pps_driver.h"
|
||||
#endif // PPS_INTEL
|
||||
|
||||
#ifdef PPS_PANFROST
|
||||
#include "panfrost/ds/pan_pps_driver.h"
|
||||
#endif // PPS_PANFROST
|
||||
|
||||
#ifdef PPS_V3D
|
||||
#include "broadcom/ds/v3d_pps_driver.h"
|
||||
#endif
|
||||
|
||||
#include "pps.h"
|
||||
#include "pps_algorithm.h"
|
||||
|
||||
namespace pps
|
||||
{
|
||||
std::unordered_map<std::string, std::unique_ptr<Driver>> create_supported_drivers()
|
||||
{
|
||||
std::unordered_map<std::string, std::unique_ptr<Driver>> map;
|
||||
|
||||
#ifdef PPS_FREEDRENO
|
||||
map.emplace("msm", std::make_unique<FreedrenoDriver>());
|
||||
#endif // PPS_FREEDRENO
|
||||
|
||||
#ifdef PPS_INTEL
|
||||
map.emplace("i915", std::make_unique<IntelDriver>());
|
||||
map.emplace("xe", std::make_unique<IntelDriver>());
|
||||
#endif // PPS_INTEL
|
||||
|
||||
#ifdef PPS_PANFROST
|
||||
map.emplace("panfrost", std::make_unique<PanfrostDriver>());
|
||||
#endif // PPS_PANFROST
|
||||
|
||||
#ifdef PPS_V3D
|
||||
map.emplace("v3d", std::make_unique<V3DDriver>());
|
||||
#endif
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, std::unique_ptr<Driver>> &Driver::get_supported_drivers()
|
||||
{
|
||||
static auto map = create_supported_drivers();
|
||||
return map;
|
||||
}
|
||||
|
||||
const std::vector<std::string> Driver::supported_device_names()
|
||||
{
|
||||
std::vector<std::string> supported_device_names;
|
||||
|
||||
for (auto &entry : get_supported_drivers()) {
|
||||
supported_device_names.emplace_back(entry.first);
|
||||
}
|
||||
|
||||
return supported_device_names;
|
||||
}
|
||||
|
||||
Driver *Driver::get_driver(DrmDevice &&drm_device)
|
||||
{
|
||||
auto &supported_drivers = get_supported_drivers();
|
||||
auto it = supported_drivers.find(drm_device.name);
|
||||
if (it == std::end(supported_drivers)) {
|
||||
PERFETTO_FATAL("Failed to find a driver for DRM device %s", drm_device.name.c_str());
|
||||
}
|
||||
|
||||
Driver *driver = it->second.get();
|
||||
driver->drm_device = std::move(drm_device);
|
||||
return driver;
|
||||
}
|
||||
|
||||
std::string Driver::default_driver_name()
|
||||
{
|
||||
auto supported_devices = Driver::supported_device_names();
|
||||
auto devices = DrmDevice::create_all();
|
||||
for (auto &device : devices) {
|
||||
if (CONTAINS(supported_devices, device.name)) {
|
||||
PPS_LOG_IMPORTANT("Driver selected: %s", device.name.c_str());
|
||||
return device.name;
|
||||
}
|
||||
}
|
||||
PPS_LOG_FATAL("Failed to find any driver");
|
||||
}
|
||||
|
||||
std::string Driver::find_driver_name(const char *requested)
|
||||
{
|
||||
auto supported_devices = Driver::supported_device_names();
|
||||
auto devices = DrmDevice::create_all();
|
||||
for (auto &device : devices) {
|
||||
if (device.name == requested) {
|
||||
PPS_LOG_IMPORTANT("Driver selected: %s", device.name.c_str());
|
||||
return device.name;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostringstream drivers_os;
|
||||
std::copy(supported_devices.begin(),
|
||||
supported_devices.end() - 1,
|
||||
std::ostream_iterator<std::string>(drivers_os, ", "));
|
||||
drivers_os << supported_devices.back();
|
||||
|
||||
PPS_LOG_ERROR(
|
||||
"Device '%s' not found (supported drivers: %s)", requested, drivers_os.str().c_str());
|
||||
|
||||
return default_driver_name();
|
||||
}
|
||||
|
||||
} // namespace pps
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright © 2020 Collabora, Ltd.
|
||||
* Author: Antonio Caggiano <[email protected]>
|
||||
* Author: Robert Beckett <[email protected]>
|
||||
* Author: Corentin Noël <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "pps_counter.h"
|
||||
#include "pps_device.h"
|
||||
|
||||
namespace pps
|
||||
{
|
||||
/// @brief Abstract Driver class
|
||||
class Driver
|
||||
{
|
||||
public:
|
||||
/// @return A map of supported DRM device names and their relative pps driver
|
||||
static const std::unordered_map<std::string, std::unique_ptr<Driver>> &get_supported_drivers();
|
||||
|
||||
/// @return A list of supported DRM device names
|
||||
static const std::vector<std::string> supported_device_names();
|
||||
|
||||
/// @return A driver supporting a specific DRM device
|
||||
static Driver *get_driver(DrmDevice &&drm_device);
|
||||
|
||||
/// @return The name of a default selected PPS driver
|
||||
static std::string default_driver_name();
|
||||
|
||||
/// @return The name of a driver based on the request, otherwise the default driver name
|
||||
static std::string find_driver_name(const char *requested_name);
|
||||
|
||||
Driver() = default;
|
||||
virtual ~Driver() = default;
|
||||
|
||||
// Forbid copy
|
||||
Driver(const Driver &) = delete;
|
||||
Driver &operator=(const Driver &) = delete;
|
||||
|
||||
/// @return Whether dump_perfcnt is preemptible
|
||||
virtual bool is_dump_perfcnt_preemptible() const { return true; }
|
||||
|
||||
/// @return The minimum sampling period for the current device
|
||||
virtual uint64_t get_min_sampling_period_ns() = 0;
|
||||
|
||||
/// @brief Enable a counter by its ID
|
||||
virtual void enable_counter(uint32_t counter_id) = 0;
|
||||
|
||||
virtual void enable_all_counters() = 0;
|
||||
|
||||
/// @brief Initialize performance counters data such as groups and counters
|
||||
/// @return Whether it was successful or not
|
||||
virtual bool init_perfcnt() = 0;
|
||||
|
||||
/// @brief Enables performance counters, meaning that from now on they can be sampled
|
||||
virtual void enable_perfcnt(uint64_t sampling_period_ns) = 0;
|
||||
|
||||
/// @brief Disables performance counters on the device
|
||||
virtual void disable_perfcnt() = 0;
|
||||
|
||||
/// @brief Asking the GPU to dump performance counters could have different meanings
|
||||
/// depending on the concrete driver. Some could just ask the GPU to dump counters to a
|
||||
/// user space buffer, while some others will need to read data from a stream which was
|
||||
/// written asynchronously.
|
||||
/// @return Whether it was able to dump, false otherwise
|
||||
virtual bool dump_perfcnt() = 0;
|
||||
|
||||
/// @brief After dumping performance counters, with this function you can iterate
|
||||
/// through the samples collected.
|
||||
/// @return The GPU timestamp associated to current sample, or 0 if there are no more samples
|
||||
virtual uint64_t next() = 0;
|
||||
|
||||
/// Clock ID in which the values returned by gpu_timestamp() belong
|
||||
virtual uint32_t gpu_clock_id() const = 0;
|
||||
|
||||
/// Sample a timestamp from the GPU
|
||||
virtual uint64_t gpu_timestamp() const = 0;
|
||||
|
||||
/// Sample a timestamp from both the CPU & the GPU
|
||||
///
|
||||
/// This is useful when the driver can do a better timestamp correlation
|
||||
/// than sampling separately CPU & GPU timestamps.
|
||||
virtual bool cpu_gpu_timestamp(uint64_t &cpu_timestamp, uint64_t &gpu_timestamp) const = 0;
|
||||
|
||||
DrmDevice drm_device;
|
||||
|
||||
/// List of counter groups
|
||||
std::vector<CounterGroup> groups;
|
||||
|
||||
/// List of counters exposed by the GPU
|
||||
std::vector<Counter> counters;
|
||||
|
||||
/// List of counters that are actually enabled
|
||||
std::vector<Counter> enabled_counters;
|
||||
|
||||
protected:
|
||||
// Prevent object slicing by allowing move only from subclasses
|
||||
Driver(Driver &&) = default;
|
||||
Driver &operator=(Driver &&) = default;
|
||||
};
|
||||
|
||||
} // namespace pps
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright © 2019-2020 Collabora, Ltd.
|
||||
* Author: Antonio Caggiano <[email protected]>
|
||||
* Author: Robert Beckett <[email protected]>
|
||||
* Author: Corentin Noël <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "util/detect_os.h"
|
||||
#include "pps_datasource.h"
|
||||
|
||||
int init(std::string &driver_name)
|
||||
{
|
||||
using namespace pps;
|
||||
|
||||
// Connects to the system tracing service
|
||||
perfetto::TracingInitArgs args;
|
||||
args.backends = perfetto::kSystemBackend;
|
||||
perfetto::Tracing::Initialize(args);
|
||||
|
||||
GpuDataSource::register_data_source(driver_name);
|
||||
|
||||
const auto &driver = Driver::get_supported_drivers().at(driver_name);
|
||||
if (!driver->is_dump_perfcnt_preemptible())
|
||||
make_thread_rt();
|
||||
|
||||
while (true) {
|
||||
GpuDataSource::wait_started();
|
||||
GpuDataSource::Trace(GpuDataSource::trace_callback);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
using namespace pps;
|
||||
std::string driver_name =
|
||||
(argc > 1) ? Driver::find_driver_name(argv[1]) : Driver::default_driver_name();
|
||||
return init(driver_name);
|
||||
}
|
||||
|
||||
#if DETECT_OS_ANDROID
|
||||
extern "C" int start()
|
||||
{
|
||||
using namespace pps;
|
||||
std::string driver_name = Driver::default_driver_name();
|
||||
return init(driver_name);
|
||||
}
|
||||
#endif
|
||||
Reference in new issue
Block a user