Commit 73de2031 authored by Antonio Caggiano's avatar Antonio Caggiano 🦀

misc: Remove weston producer

Planning to move the weston producer in its own repository within the
weston namespace, we remove it from this project.
Signed-off-by: Antonio Caggiano's avatarAntonio Caggiano <antonio.caggiano@collabora.com>
Acked-by: default avatarRohan Garg <rohan.garg@collabora.com>
parent 49cded4a
Pipeline #254674 passed with stages
in 2 minutes and 10 seconds
......@@ -4,7 +4,6 @@ Graphics Perfetto producers
This project contains a collection of graphics-related [Perfetto producers](https://perfetto.dev/#/architecture.md). A producer is a client process for the Perfetto tracing service. Currently available are the following producers:
- Panfrost performance counters
- Weston timeline debug stream
- Intel performance counters
## Build
......@@ -129,7 +128,7 @@ To capture a trace with perfetto you need to take the following steps:
CONFIG=test.cfg OUT=out/build ./tools/tmux
```
4. Start other producers you may need, like `producer-gpu` or `producer-weston`.
4. Start other producers you may need, like `producer-gpu`.
5. Start perfetto under the tmux session initiated in step 3.
......@@ -167,22 +166,6 @@ The Intel driver needs root access to read system-wide [RenderBasic]() performan
sudo ./build/producer-gpu
```
### Weston producer
The weston producer needs the debug protocol to be present in weston. If the debug protocol is not present, update weston or install the latest development version from git.
1. Before running `producer-weston`, make sure weston is started with the `--debug` argument:
```sh
weston --debug
```
2. Execute the producer:
```sh
./build/producer-weston
```
## Troubleshooting
### Tmux
......
/*
* Copyright (c) 2020 Collabora, Ltd.
* Author: Antonio Caggiano <antonio.caggiano@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <array>
#include <optional>
#include <rapidjson/document.h>
#include <string>
#include <vector>
#include "weston_ds.h"
namespace pps::weston
{
using TimelineBuffer = std::vector<char>;
class Parser
{
public:
/// @brief Parses a buffer containing JSON weston timeline events
/// @return The list of event parsed from the timeline and the number of chars parsed correcly
std::pair<std::vector<WestonTimepoint>, size_t> parse(const TimelineBuffer &buffer);
/// @return The list of objects parsed so far
const std::vector<WestonObject> &get_objects() const
{
return objects;
}
/// @return The weston object with that ID; nullptr if not found
WestonObject *get_object(WestonId id);
/// @return The number of errors accumulated during all parsing
size_t get_error_count() const
{
return error_count;
}
private:
/// @brief Adds a new weston object, or updates an old one if already present
void add_or_update(WestonObject &&obj);
/// @brief Parses a json respresentation of a @ref WestonTimepoint
/// @return Some newly created weston timepoints
std::vector<WestonTimepoint> parse_timepoint(const rapidjson::Document &doc);
/// Keeps track of the number of errors
size_t error_count = 0;
/// Store weston objects as they are parsed
std::vector<WestonObject> objects;
};
} // namespace pps::weston
/*
* Copyright (c) 2019-2020 Collabora, Ltd.
* Author: Aguado Puig, Quim <quim.aguado@collabora.com>
* Author: Antonio Caggiano <antonio.caggiano@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <pps/pds.h>
#include <weston-debug-client-protocol.h>
#include "pps/weston/parser.h"
#include "pps/weston/track.h"
namespace pps::weston
{
/// @return A buffer of bytes read from a file descriptor
TimelineBuffer read_buffer(int fd);
class TimelineDataSource final : public perfetto::DataSource<TimelineDataSource>
{
public:
~TimelineDataSource() override
{
reset();
}
static const char *get_name()
{
return "weston.debug.timeline";
}
static const char *get_stream_name()
{
return "timeline";
}
/// @brief File path to read to parse json weston timeline.
/// If it is null (default), the data source connects to weston
static const char *read_file;
/// @return The current state of this data-source
static State get_state()
{
return state;
}
/// @brief Perfetto trace callback
static void trace_callback(TraceContext ctx);
/// Perfetto callbacks
void OnSetup(const SetupArgs &args) override;
void OnStart(const StartArgs &args) override;
void OnStop(const StopArgs &args) override;
/// @return The weston parser used by this data source
const Parser &get_parser() const
{
return parser;
}
/// @brief Reads bytes from a file descriptor until EOF
/// to parse weston objects and timepoints
/// @param read_fd File descriptor to read from
std::vector<WestonTimepoint> read_timepoints(int read_fd);
private:
/// @brief To be called on reset state
void reset();
void sample();
/// Weston debug callbacks
static void global_add(void *data,
wl_registry *registry,
uint32_t id,
const char *interface,
uint32_t version);
static void global_remove(void *data, wl_registry *registry, uint32_t id);
static void
debug_available(void *data, weston_debug_v1 *debug, const char *name, const char *description);
static void handle_stream_failure(void *data, weston_debug_stream_v1 *stream, const char *msg);
static void handle_stream_complete(void *data, weston_debug_stream_v1 *stream);
/// @brief Perfetto callback helper
/// If not already sent, it sends a new track descriptor
void send_track_descriptor(const Track &track, const Track *parent = nullptr);
/// @brief This perfetto callback helper sends a new track event for a timepoint
/// associating it to the thread track of the surface, or output, it refers to
void send_track_event(const WestonTimepoint &timepoint,
perfetto::protos::pbzero::TrackEvent::Type type);
/// @brief Send a trace packet for a weston timepoint
/// @param ctx Trace context used to create the packet
/// @param event Weston timepoint event to trace
void send_packet(WestonTimepoint &event);
static State state;
// Keep track of current context to avoid passing it around in helper functions
TraceContext *ctx = nullptr;
wl_display *display = nullptr;
wl_registry *registry = nullptr;
const weston_debug_v1_listener debug_listener = {debug_available};
const wl_registry_listener registry_listener = {
.global = global_add,
.global_remove = global_remove,
};
const weston_debug_stream_v1_listener stream_listener = {
handle_stream_complete,
handle_stream_failure,
};
bool stream_complete = false;
weston_debug_stream_v1 *stream = nullptr;
/// Read and write ends of a pipe
int read_fd = -1;
int write_fd = -1;
/// Used to store butes read from the pipe
TimelineBuffer json_buffer = TimelineBuffer();
/// Used to parse a json string into weston timeline events
Parser parser = Parser();
/// Perfetto parent tracks
std::vector<TrackId> parent_tracks;
/// Perfetto tracks
std::vector<TrackId> tracks;
weston_debug_v1 *debug_iface = nullptr;
bool stream_exists = false;
};
} // namespace pps::weston
#pragma once
#include <pps/perfetto/perfetto.h>
#include <string>
namespace pps::weston
{
class WestonObject;
class WestonTimepoint;
class TimelineDataSource;
using TrackId = uint64_t;
/// @brief Helper class which defines a Perfetto track
struct Track {
TrackId id = 0;
std::string name = "Undefined";
void send(const WestonTimepoint &event,
perfetto::protos::pbzero::TrackEvent::Type type,
protozero::MessageHandle<perfetto::protos::pbzero::TracePacket> packet);
};
/// @param output Tracks are grouped by output
/// @param surface Is surface is null the returned track is associated only with the output
/// @return A track for the pair output/surface
Track get_track(const WestonObject &output, const WestonObject *surface = nullptr);
/// @param output Output used for grouping child tracks
/// @return A parent track which groups tracks related to the same output
Track get_parent_track(const WestonObject &output);
/// @param output Output referred by the returned track
/// @return A track for vblank slices
Track get_vblank_track(const WestonObject &output);
/// @param output Output referred by the returned track
/// @return A track for repaint required and repaint delay slices
Track get_repaint_req_track(const WestonObject &output);
} // namespace pps::weston
#pragma once
#include <optional>
#include <string>
namespace pps::weston
{
using WestonId = uint32_t;
struct WestonTimepoint {
enum class Type {
UNDEFINED,
// Client submitting a new frame
CORE_COMMIT_DAMAGE,
CORE_FLUSH_DAMAGE,
CORE_REPAINT_BEGIN,
CORE_REPAINT_END,
CORE_KMS_FLIP_BEGIN,
CORE_KMS_FLIP_END,
CORE_REPAINT_ENTER_LOOP,
CORE_REPAINT_EXIT_LOOP,
// Repaint has been requested
CORE_REPAINT_REQ_BEGIN,
CORE_REPAINT_REQ_END,
CORE_REPAINT_DELAY_BEGIN,
CORE_REPAINT_DELAY_END,
RENDERER_GPU_BEGIN,
RENDERER_GPU_END,
VBLANK_BEGIN,
VBLANK_END,
MAX,
};
uint64_t get_timestamp() const
{
return ts.tv_sec * 1000000000 + ts.tv_nsec;
}
timespec ts = {};
std::string name = "";
Type type = Type::UNDEFINED;
WestonId output = 0;
WestonId surface = 0;
};
struct WestonObject {
enum class Type { UNDEFINED, SURFACE, OUTPUT, MAX };
WestonId id = 0;
Type type = Type::UNDEFINED;
std::string name;
std::string description;
/// Since not always a commit damage is followed by a flush we store last
/// commit damage of a surface and only generate a slice when we get a flush.
/// If we instead get another commit, we generate an instant event for
/// the previous commit, and overwrite last commit with the new one.
std::optional<WestonTimepoint> last_damage;
/// Keep track of repaint required timepoint, so we can consume it when repaint finishes
bool repaint_required = false;
/// Kep track of repaint delay, so we can consue it when repaint starts again
bool repaint_delay = false;
/// @return Whether two weston objects have the same ID
bool operator==(const WestonObject &oth) const
{
return id == oth.id;
}
};
std::string to_string(const WestonObject &wo);
} // namespace pps::weston
option('weston', type: 'boolean', value: true, description: 'Whether to build weston producer')
option('gpu', type: 'boolean', value: true, description: 'Whether to build gpu producer')
option('test', type: 'boolean', value: true, description: 'Whether to build tests')
option('doc', type: 'boolean', value: false, description: 'Whether to build documentation')
buffers {
size_kb: 65536
fill_policy: RING_BUFFER
}
data_sources {
config {
name: "weston.debug.timeline"
target_buffer: 0
}
}
data_sources {
config {
name: "perfetto.metatrace"
target_buffer: 0
}
}
producers {
producer_name: "perfetto.traced_probes"
shm_size_kb: 4096
page_size_kb: 4
}
duration_ms: 10000
......@@ -5,9 +5,6 @@
subdir('perfetto')
subdir('pps')
if get_option('weston')
subdir('weston')
endif
if get_option('gpu')
subdir('gpu')
endif
# Copyright (c) 2018-2020 Collabora, Ltd.
# Author: Daniel Stone <daniels@collabora.com>
# Author: Pekka Paalanen <pekka.paalanen@collabora.com>
# Author: Alexandros Frantzis <alexandros.frantzis@collabora.com>
# Author: Scott Anderson <scott.anderson@collabora.com>
# Author: Jonas Ådahl <jadahl@gmail.com>
# Author: Marius Vlad <marius.vlad@collabora.com>
# Author: Antonio Caggiano <antonio.caggiano@collabora.com>
#
# SPDX-License-Identifier: MIT
dep_scanner = dependency('wayland-scanner', native: true)
prog_scanner = find_program(dep_scanner.get_pkgconfig_variable('wayland_scanner'))
dep_weston_protocols = dependency('libweston-8-protocols')
dir_weston_protocols_base = dep_weston_protocols.get_pkgconfig_variable('pkgdatadir')
base_file = 'weston-debug'
xml_path = '@0@/@1@.xml'.format(dir_weston_protocols_base, base_file)
foreach output_type: [ 'client-header', 'private-code' ]
if output_type == 'client-header'
output_file = '@0@-client-protocol.h'.format(base_file)
else
output_file = '@0@-protocol.c'.format(base_file)
if dep_scanner.version().version_compare('< 1.14.91')
output_type = 'code'
endif
endif
var_name = output_file.underscorify()
target = custom_target(
'@0@ @1@'.format(base_file, output_type),
command: [ prog_scanner, output_type, '@INPUT@', '@OUTPUT@' ],
input: xml_path,
output: output_file,
)
set_variable(var_name, target)
endforeach
# Lib weston debug
weston_debug_sources = [weston_debug_client_protocol_h, weston_debug_protocol_c]
lib_weston_debug = static_library('weston-debug', weston_debug_sources)
dep_weston_debug = declare_dependency(sources: weston_debug_sources,link_with: lib_weston_debug)
/*
* Copyright (c) 2020 Collabora, Ltd.
* Author: Antonio Caggiano <antonio.caggiano@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include <cstdlib>
#include <sys/stat.h>
#include <sys/types.h>
#include <thread>
#include <unistd.h>
#include <pps/weston/timeline_ds.h>
int main(int argc, const char **argv)
{
using namespace pps;
// Default behaviour is data source connects to weston as a client
// and parses the json weston timeline through its debug protocol.
// When a command line argument is passed, the data source will
// try to open it to parse its content as json weston timeline.
if (argc == 2) {
struct stat stat_buf;
if (stat(argv[1], &stat_buf) < 0) {
PERFETTO_FATAL("Failed checking file");
}
weston::TimelineDataSource::read_file = argv[1];
}
// Connects to the system tracing service
perfetto::TracingInitArgs args;
args.backends = perfetto::kSystemBackend;
perfetto::Tracing::Initialize(args);
perfetto::DataSourceDescriptor dsd;
dsd.set_name(weston::TimelineDataSource::get_name());
weston::TimelineDataSource::Register(dsd);
while (true) {
switch (weston::TimelineDataSource::get_state()) {
using namespace std::chrono_literals;
case State::Stop: {
// Just wait until it starts
std::this_thread::sleep_for(2ms);
break;
}
case State::Start: {
weston::TimelineDataSource::Trace(weston::TimelineDataSource::trace_callback);
/// @todo Can this time be specified by a perfetto config file?
std::this_thread::sleep_for(2ms);
break;
}
default: {
assert(false && "Invalid DataSource state");
}
}
}
return EXIT_SUCCESS;
}
# Copyright (c) 2020 Collabora, Ltd.
# Author: Antonio Caggiano <antonio.caggiano@collabora.com>
#
# SPDX-License-Identifier: MIT
# Weston debug lib
subdir('debug')
# Find wayland client
wayland_client = dependency('wayland-client')
# Weston data source
wtds_sources = [
'timeline_ds.cc',
'parser.cc',
'track.cc' ]
lib_pps_weston = static_library(
'pps-weston',
wtds_sources,
include_directories: include_pps,
dependencies: [dep_weston_debug, wayland_client]
)
dep_pps_weston = declare_dependency(
link_with: lib_pps_weston,
include_directories: include_pps,
dependencies: [dep_weston_debug, dep_perfetto]
)
# Weston producer
executable(
'producer-weston',
'main.cc',
dependencies: [dep_pps_weston, dep_perfetto],
install: true
)
/*
* Copyright (c) 2020 Collabora, Ltd.
* Author: Antonio Caggiano <antonio.caggiano@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include "pps/weston/parser.h"
#include <pps/perfetto/perfetto.h>
#include "pps/algorithm.h"
namespace pps::weston
{
/// @return A timestamp (ns) representation of the timespec
uint64_t to_timestamp(timespec ts)
{
return ts.tv_sec * 1000000000 + ts.tv_nsec;
}
timespec min(timespec a, timespec b)
{
return to_timestamp(a) < to_timestamp(b) ? a : b;
}
timespec max(timespec a, timespec b)
{
return to_timestamp(a) > to_timestamp(b) ? a : b;
}
std::string to_string(const WestonObject &wo)
{
if (!wo.name.empty()) {
return wo.name;
} else {
return wo.description;
}
}
/// @return Conversion of a string to a weston object type
WestonObject::Type object_from_string(const std::string_view &name)
{
if (name == "weston_surface") {
return WestonObject::Type::SURFACE;
} else if (name == "weston_output") {
return WestonObject::Type::OUTPUT;
}
PERFETTO_ELOG("Unknown weston object type: %s", name.data());
return WestonObject::Type::UNDEFINED;
}
/// @return Conversion of a string to a weston timepoint type
WestonTimepoint::Type timepoint_from_string(const std::string_view &name)
{
if (name == "core_commit_damage") {
return WestonTimepoint::Type::CORE_COMMIT_DAMAGE;
} else if (name == "core_flush_damage") {
return WestonTimepoint::Type::CORE_FLUSH_DAMAGE;
} else if (name == "core_repaint_begin") {
return WestonTimepoint::Type::CORE_REPAINT_BEGIN;
} else if (name == "core_repaint_finished") {
return WestonTimepoint::Type::CORE_KMS_FLIP_END;