libweston: Add frame commit frame rate counting

This is a continuation of work from
https://gitlab.freedesktop.org/wayland/weston/-/merge_requests/24

This patch adds a surface callback frame rate counter to the scene-graph
debug scope.

The timer interval is set by default to 1 second. This use a timer to
periodically compute the current frame callback commits in that interval
as the surface frame rate per timer interval.  Note that is solely based on
wl_surface::commit call.

Together with this, this patch also adds perfetto counter that stores
the same computed frame rate. This means the counter will be updated on
the next interval timer when the timer is armed/fired such that that
perfetto drawings will show up in a window period of time (interval).

Helpful to identify what frame rates clients achieve to debug
performance issues as to provide an objective common group. Using the
debug-scope aggregates all surfaces at the same place. This is not based
on the GPU whatsoever so it can also work on SHM type of buffers.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
Signed-off-by: Changwoo Cho <changwoo.cho@lge.com>
This commit is contained in:
Marius Vlad 2024-05-23 12:19:54 +03:00
parent ad3957ddf8
commit e850e97ab7
2 changed files with 122 additions and 0 deletions

View file

@ -1655,6 +1655,14 @@ struct weston_compositor {
struct wl_global *weston_capture_v1;
struct wl_signal ask_auth;
} output_capture;
struct {
/** interval which we divide the amount of frames */
unsigned int frame_counter_interval;
/** fires with frame_counter_interval rate */
struct wl_event_source *frame_counter_timer;
} perf_surface_stats;
};
struct weston_solid_buffer_values {
@ -2103,6 +2111,14 @@ struct weston_surface {
uint64_t damage_track_id;
uint64_t flow_id;
/** increments for each wl_surface::commit,
* reset after each frame counter interval */
unsigned int frame_commit_counter;
/** computed after each frame_counter_interval */
float frame_commit_fps_counter;
};
struct weston_subsurface {

View file

@ -98,6 +98,7 @@
*/
#define DEFAULT_REPAINT_WINDOW 7 /* milliseconds */
#define DEFAULT_FRAME_RATE_INTERVAL 1 /* seconds */
static void
weston_output_transform_scale_init(struct weston_output *output,
@ -3990,6 +3991,86 @@ weston_output_schedule_repaint_restart(struct weston_output *output)
weston_output_damage(output);
}
static void
surface_frame_rate_stats(void *data)
{
struct weston_surface *surf = data;
struct weston_compositor *compositor = surf->compositor;
uint32_t frame_counter_interval =
compositor->perf_surface_stats.frame_counter_interval;
if (surf->resource) {
char surface_desc[512];
char p_counter_fc_counter[1024];
if (surf->get_label)
surf->get_label(surf, surface_desc, sizeof(surface_desc));
else {
uint32_t res_id;
res_id = wl_resource_get_id(surf->resource);
snprintf(surface_desc, sizeof(surface_desc),
"unlabelled surface %d", res_id);
}
surf->frame_commit_fps_counter =
(float) (surf->frame_commit_counter / frame_counter_interval);
snprintf(p_counter_fc_counter, sizeof(p_counter_fc_counter),
"%s #%d", (char *) surface_desc, surf->s_id);
WESTON_TRACE_SET_COUNTER(p_counter_fc_counter,
surf->frame_commit_fps_counter);
}
surf->frame_commit_counter = 0;
}
static void
for_each_view_in_each_layer(struct weston_compositor *compositor,
void (*callback)(void *data))
{
struct weston_layer *layer;
struct weston_view *view;
wl_list_for_each(layer, &compositor->layer_list, link)
wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
struct weston_subsurface *sub;
struct weston_view *ev;
/* the main, parent-surface */
callback(view->surface);
if (wl_list_empty(&view->surface->subsurface_list))
continue;
wl_list_for_each(sub, &view->surface->subsurface_list,
parent_link)
wl_list_for_each(ev, &sub->surface->views,
surface_link) {
if (ev->parent_view != view)
continue;
callback(ev->surface);
}
}
}
static int
surface_statistics_timer_handler(void *data)
{
struct weston_compositor *comp = data;
unsigned frm_cnt_int = comp->perf_surface_stats.frame_counter_interval;
struct wl_event_source *frm_cnt_timer =
comp->perf_surface_stats.frame_counter_timer;
for_each_view_in_each_layer(comp, surface_frame_rate_stats);
wl_event_source_timer_update(frm_cnt_timer, 1000 * frm_cnt_int);
return 0;
}
static int
output_repaint_timer_handler(void *data)
{
@ -4894,6 +4975,7 @@ weston_surface_commit_state(struct weston_surface *surface,
&state->damage_surface);
apply_damage_buffer(&surface->damage, surface, state);
surface->frame_commit_counter++;
pixman_region32_intersect_rect(&surface->damage,
&surface->damage,
@ -9475,6 +9557,13 @@ debug_scene_view_print(FILE *fp, struct weston_view *view, int view_idx)
fprintf(fp, "\n");
debug_scene_view_print_buffer(fp, view);
if (weston_surface_is_mapped(view->surface)) {
fprintf(fp, "\t\tCommit frame rate: %2.2f sampled interval: %dsec)\n",
view->surface->frame_commit_fps_counter,
ec->perf_surface_stats.frame_counter_interval);
}
}
static void
@ -9596,6 +9685,20 @@ weston_compositor_print_scene_graph(struct weston_compositor *ec)
return ret;
}
static void
weston_compositor_create_surface_counter_fps(struct weston_compositor *ec, uint32_t interval)
{
struct wl_event_loop *loop = wl_display_get_event_loop(ec->wl_display);
ec->perf_surface_stats.frame_counter_interval = interval;
ec->perf_surface_stats.frame_counter_timer =
wl_event_loop_add_timer(loop, surface_statistics_timer_handler, ec);
wl_event_source_timer_update(ec->perf_surface_stats.frame_counter_timer,
1000 * ec->perf_surface_stats.frame_counter_interval);
}
/**
* Called when the 'scene-graph' debug scope is bound by a client. This
* one-shot weston-debug scope prints the current scene graph when bound,
@ -9768,6 +9871,8 @@ weston_compositor_create(struct wl_display *display,
wl_event_loop_add_timer(loop, output_repaint_timer_handler,
ec);
weston_compositor_create_surface_counter_fps(ec, DEFAULT_FRAME_RATE_INTERVAL);
weston_layer_init(&ec->fade_layer, ec);
weston_layer_init(&ec->cursor_layer, ec);
@ -9810,6 +9915,7 @@ weston_compositor_shutdown(struct weston_compositor *ec)
wl_event_source_remove(ec->idle_source);
wl_event_source_remove(ec->repaint_timer);
wl_event_source_remove(ec->perf_surface_stats.frame_counter_timer);
if (ec->touch_calibration)
weston_compositor_destroy_touch_calibrator(ec);