libweston: Introduce timeline subscription and timeline subscription object
An object based on 'weston_timeline_subscription' will be created for each subscription created. It contains the next object ID and list of 'weston_timeline_subscription_object'. It will automatically be cleaned by the logging framework when the subscription gets destroyed, or use the object destroy signal to trigger the destruction of the timeline subscription (@pq), when the object itself is being destroyed. This class will hanged-off the subscription, such that we can retrieve it when going over all the subscriptions. An object based on 'weston_timeline_subscription_object' will help maintain the state of the objects seen and will be created when a new object will be emitted for a particular 'weston_timeline_subscription'. Adds wrappers for ensuring the timeline subscription object is created or has to be searched in order to be found, as to avoid duplicated code. Signed-off-by: Marius Vlad <marius.vlad@collabora.com> Suggested-by: Daniel Stone <daniel.stone@collabora.com>
This commit is contained in:
+199
-53
@@ -32,91 +32,229 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include "timeline.h"
|
|
||||||
#include <libweston/libweston.h>
|
#include <libweston/libweston.h>
|
||||||
|
#include <libweston/weston-log.h>
|
||||||
|
#include "timeline.h"
|
||||||
|
#include "weston-log-internal.h"
|
||||||
|
|
||||||
WL_EXPORT int weston_timeline_enabled_;
|
WL_EXPORT int weston_timeline_enabled_;
|
||||||
|
|
||||||
struct timeline_emit_context {
|
struct timeline_emit_context {
|
||||||
FILE *cur;
|
FILE *cur;
|
||||||
FILE *out;
|
struct weston_log_subscription *subscription;
|
||||||
unsigned series;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned
|
/** Create a timeline subscription and hang it off the subscription
|
||||||
timeline_new_id(void)
|
*
|
||||||
|
* Called when the subscription is created.
|
||||||
|
*
|
||||||
|
* @ingroup internal-log
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
weston_timeline_create_subscription(struct weston_log_subscription *sub,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
static unsigned idc;
|
struct weston_timeline_subscription *tl_sub = zalloc(sizeof(*tl_sub));
|
||||||
|
if (!tl_sub)
|
||||||
|
return;
|
||||||
|
|
||||||
if (++idc == 0)
|
wl_list_init(&tl_sub->objects);
|
||||||
++idc;
|
|
||||||
|
|
||||||
return idc;
|
/* attach this timeline_subscription to it */
|
||||||
}
|
weston_log_subscription_set_data(sub, tl_sub);
|
||||||
|
|
||||||
static int
|
|
||||||
check_series(struct timeline_emit_context *ctx,
|
|
||||||
struct weston_timeline_object *to)
|
|
||||||
{
|
|
||||||
if (to->series == 0 || to->series != ctx->series) {
|
|
||||||
to->series = ctx->series;
|
|
||||||
to->id = timeline_new_id();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (to->force_refresh) {
|
|
||||||
to->force_refresh = 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fprint_quoted_string(FILE *fp, const char *str)
|
weston_timeline_destroy_subscription_object(struct weston_timeline_subscription_object *sub_obj)
|
||||||
|
{
|
||||||
|
/* remove the notify listener */
|
||||||
|
wl_list_remove(&sub_obj->destroy_listener.link);
|
||||||
|
sub_obj->destroy_listener.notify = NULL;
|
||||||
|
|
||||||
|
wl_list_remove(&sub_obj->subscription_link);
|
||||||
|
free(sub_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Destroy the timeline subscription and all timeline subscription objects
|
||||||
|
* associated with it.
|
||||||
|
*
|
||||||
|
* Called when (before) the subscription is destroyed.
|
||||||
|
*
|
||||||
|
* @ingroup internal-log
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
weston_timeline_destroy_subscription(struct weston_log_subscription *sub,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct weston_timeline_subscription *tl_sub =
|
||||||
|
weston_log_subscription_get_data(sub);
|
||||||
|
struct weston_timeline_subscription_object *sub_obj, *tmp_sub_obj;
|
||||||
|
|
||||||
|
if (!tl_sub)
|
||||||
|
return;
|
||||||
|
|
||||||
|
wl_list_for_each_safe(sub_obj, tmp_sub_obj,
|
||||||
|
&tl_sub->objects, subscription_link)
|
||||||
|
weston_timeline_destroy_subscription_object(sub_obj);
|
||||||
|
|
||||||
|
free(tl_sub);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
weston_timeline_check_object_refresh(struct weston_timeline_subscription_object *obj)
|
||||||
|
{
|
||||||
|
if (obj->force_refresh == true) {
|
||||||
|
obj->force_refresh = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct weston_timeline_subscription_object *
|
||||||
|
weston_timeline_subscription_search(struct weston_timeline_subscription *tl_sub,
|
||||||
|
void *object)
|
||||||
|
{
|
||||||
|
struct weston_timeline_subscription_object *sub_obj;
|
||||||
|
|
||||||
|
wl_list_for_each(sub_obj, &tl_sub->objects, subscription_link)
|
||||||
|
if (sub_obj->object == object)
|
||||||
|
return sub_obj;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct weston_timeline_subscription_object *
|
||||||
|
weston_timeline_subscription_object_create(void *object,
|
||||||
|
struct weston_timeline_subscription *tm_sub)
|
||||||
|
{
|
||||||
|
struct weston_timeline_subscription_object *sub_obj;
|
||||||
|
|
||||||
|
sub_obj = zalloc(sizeof(*sub_obj));
|
||||||
|
sub_obj->id = ++tm_sub->next_id;
|
||||||
|
sub_obj->object = object;
|
||||||
|
|
||||||
|
/* when the object is created so that it has the chance to display the
|
||||||
|
* object ID, we set the refresh status; it will only be re-freshed by
|
||||||
|
* the backend (or part parts) when the underlying objects has suffered
|
||||||
|
* modifications */
|
||||||
|
sub_obj->force_refresh = true;
|
||||||
|
|
||||||
|
wl_list_insert(&tm_sub->objects, &sub_obj->subscription_link);
|
||||||
|
|
||||||
|
return sub_obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
weston_timeline_destroy_subscription_object_notify(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
struct weston_timeline_subscription_object *sub_obj;
|
||||||
|
|
||||||
|
sub_obj = wl_container_of(listener, sub_obj, destroy_listener);
|
||||||
|
weston_timeline_destroy_subscription_object(sub_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct weston_timeline_subscription_object *
|
||||||
|
weston_timeline_subscription_output_ensure(struct weston_timeline_subscription *tl_sub,
|
||||||
|
struct weston_output *output)
|
||||||
|
{
|
||||||
|
struct weston_timeline_subscription_object *sub_obj;
|
||||||
|
|
||||||
|
sub_obj = weston_timeline_subscription_search(tl_sub, output);
|
||||||
|
if (!sub_obj) {
|
||||||
|
sub_obj = weston_timeline_subscription_object_create(output, tl_sub);
|
||||||
|
|
||||||
|
sub_obj->destroy_listener.notify =
|
||||||
|
weston_timeline_destroy_subscription_object_notify;
|
||||||
|
wl_signal_add(&output->destroy_signal,
|
||||||
|
&sub_obj->destroy_listener);
|
||||||
|
}
|
||||||
|
return sub_obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct weston_timeline_subscription_object *
|
||||||
|
weston_timeline_subscription_surface_ensure(struct weston_timeline_subscription *tl_sub,
|
||||||
|
struct weston_surface *surface)
|
||||||
|
{
|
||||||
|
struct weston_timeline_subscription_object *sub_obj;
|
||||||
|
|
||||||
|
sub_obj = weston_timeline_subscription_search(tl_sub, surface);
|
||||||
|
if (!sub_obj) {
|
||||||
|
sub_obj = weston_timeline_subscription_object_create(surface, tl_sub);
|
||||||
|
|
||||||
|
sub_obj->destroy_listener.notify =
|
||||||
|
weston_timeline_destroy_subscription_object_notify;
|
||||||
|
wl_signal_add(&surface->destroy_signal,
|
||||||
|
&sub_obj->destroy_listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sub_obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fprint_quoted_string(struct weston_log_subscription *sub, const char *str)
|
||||||
{
|
{
|
||||||
if (!str) {
|
if (!str) {
|
||||||
fprintf(fp, "null");
|
weston_log_subscription_printf(sub, "null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(fp, "\"%s\"", str);
|
weston_log_subscription_printf(sub, "\"%s\"", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
emit_weston_output_print_id(struct weston_log_subscription *sub,
|
||||||
|
struct weston_timeline_subscription_object *sub_obj,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
if (!weston_timeline_check_object_refresh(sub_obj))
|
||||||
|
return;
|
||||||
|
|
||||||
|
weston_log_subscription_printf(sub, "{ \"id\":%u, "
|
||||||
|
"\"type\":\"weston_output\", \"name\":", sub_obj->id);
|
||||||
|
fprint_quoted_string(sub, name);
|
||||||
|
weston_log_subscription_printf(sub, " }\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
emit_weston_output(struct timeline_emit_context *ctx, void *obj)
|
emit_weston_output(struct timeline_emit_context *ctx, void *obj)
|
||||||
{
|
{
|
||||||
struct weston_output *o = obj;
|
struct weston_log_subscription *sub = ctx->subscription;
|
||||||
|
struct weston_output *output = obj;
|
||||||
|
struct weston_timeline_subscription_object *sub_obj;
|
||||||
|
struct weston_timeline_subscription *tl_sub;
|
||||||
|
|
||||||
if (check_series(ctx, &o->timeline)) {
|
tl_sub = weston_log_subscription_get_data(sub);
|
||||||
fprintf(ctx->out, "{ \"id\":%u, "
|
sub_obj = weston_timeline_subscription_output_ensure(tl_sub, output);
|
||||||
"\"type\":\"weston_output\", \"name\":",
|
emit_weston_output_print_id(sub, sub_obj, output->name);
|
||||||
o->timeline.id);
|
|
||||||
fprint_quoted_string(ctx->out, o->name);
|
|
||||||
fprintf(ctx->out, " }\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(ctx->cur, "\"wo\":%u", o->timeline.id);
|
assert(sub_obj->id != 0);
|
||||||
|
fprintf(ctx->cur, "\"wo\":%u", sub_obj->id);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
check_weston_surface_description(struct timeline_emit_context *ctx,
|
check_weston_surface_description(struct weston_log_subscription *sub,
|
||||||
struct weston_surface *s)
|
struct weston_surface *s,
|
||||||
|
struct weston_timeline_subscription *tm_sub,
|
||||||
|
struct weston_timeline_subscription_object *sub_obj)
|
||||||
{
|
{
|
||||||
struct weston_surface *mains;
|
struct weston_surface *mains;
|
||||||
char d[512];
|
char d[512];
|
||||||
char mainstr[32];
|
char mainstr[32];
|
||||||
|
|
||||||
if (!check_series(ctx, &s->timeline))
|
if (!weston_timeline_check_object_refresh(sub_obj))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mains = weston_surface_get_main_surface(s);
|
mains = weston_surface_get_main_surface(s);
|
||||||
if (mains != s) {
|
if (mains != s) {
|
||||||
check_weston_surface_description(ctx, mains);
|
struct weston_timeline_subscription_object *new_sub_obj;
|
||||||
if (snprintf(mainstr, sizeof(mainstr),
|
|
||||||
", \"main_surface\":%u", mains->timeline.id) < 0)
|
new_sub_obj = weston_timeline_subscription_surface_ensure(tm_sub, mains);
|
||||||
|
check_weston_surface_description(sub, mains, tm_sub, new_sub_obj);
|
||||||
|
if (snprintf(mainstr, sizeof(mainstr), ", \"main_surface\":%u",
|
||||||
|
new_sub_obj->id) < 0)
|
||||||
mainstr[0] = '\0';
|
mainstr[0] = '\0';
|
||||||
} else {
|
} else {
|
||||||
mainstr[0] = '\0';
|
mainstr[0] = '\0';
|
||||||
@@ -125,19 +263,27 @@ check_weston_surface_description(struct timeline_emit_context *ctx,
|
|||||||
if (!s->get_label || s->get_label(s, d, sizeof(d)) < 0)
|
if (!s->get_label || s->get_label(s, d, sizeof(d)) < 0)
|
||||||
d[0] = '\0';
|
d[0] = '\0';
|
||||||
|
|
||||||
fprintf(ctx->out, "{ \"id\":%u, "
|
weston_log_subscription_printf(sub, "{ \"id\":%u, "
|
||||||
"\"type\":\"weston_surface\", \"desc\":", s->timeline.id);
|
"\"type\":\"weston_surface\", \"desc\":",
|
||||||
fprint_quoted_string(ctx->out, d[0] ? d : NULL);
|
sub_obj->id);
|
||||||
fprintf(ctx->out, "%s }\n", mainstr);
|
fprint_quoted_string(sub, d[0] ? d : NULL);
|
||||||
|
weston_log_subscription_printf(sub, "%s }\n", mainstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
emit_weston_surface(struct timeline_emit_context *ctx, void *obj)
|
emit_weston_surface(struct timeline_emit_context *ctx, void *obj)
|
||||||
{
|
{
|
||||||
struct weston_surface *s = obj;
|
struct weston_log_subscription *sub = ctx->subscription;
|
||||||
|
struct weston_surface *surface = obj;
|
||||||
|
struct weston_timeline_subscription_object *sub_obj;
|
||||||
|
struct weston_timeline_subscription *tl_sub;
|
||||||
|
|
||||||
check_weston_surface_description(ctx, s);
|
tl_sub = weston_log_subscription_get_data(sub);
|
||||||
fprintf(ctx->cur, "\"ws\":%u", s->timeline.id);
|
sub_obj = weston_timeline_subscription_surface_ensure(tl_sub, surface);
|
||||||
|
check_weston_surface_description(sub, surface, tl_sub, sub_obj);
|
||||||
|
|
||||||
|
assert(sub_obj->id != 0);
|
||||||
|
fprintf(ctx->cur, "\"ws\":%u", sub_obj->id);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -214,7 +360,7 @@ weston_timeline_point(const char *name, ...)
|
|||||||
if (ferror(ctx.cur)) {
|
if (ferror(ctx.cur)) {
|
||||||
weston_log("Timeline error in constructing entry, closing.\n");
|
weston_log("Timeline error in constructing entry, closing.\n");
|
||||||
} else {
|
} else {
|
||||||
fprintf(ctx.out, "%s", buf);
|
weston_log_subscription_printf(ctx.subscription, "%s", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(ctx.cur);
|
fclose(ctx.cur);
|
||||||
|
|||||||
@@ -27,6 +27,12 @@
|
|||||||
#ifndef WESTON_TIMELINE_H
|
#ifndef WESTON_TIMELINE_H
|
||||||
#define WESTON_TIMELINE_H
|
#define WESTON_TIMELINE_H
|
||||||
|
|
||||||
|
#include <wayland-util.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include <libweston/weston-log.h>
|
||||||
|
#include <wayland-server-core.h>
|
||||||
|
|
||||||
extern int weston_timeline_enabled_;
|
extern int weston_timeline_enabled_;
|
||||||
|
|
||||||
enum timeline_type {
|
enum timeline_type {
|
||||||
@@ -37,6 +43,23 @@ enum timeline_type {
|
|||||||
TLT_GPU,
|
TLT_GPU,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct weston_timeline_subscription {
|
||||||
|
unsigned int next_id;
|
||||||
|
struct wl_list objects; /**< weston_timeline_subscription_object::subscription_link */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created when object is first seen for a particular timeline subscription
|
||||||
|
* Destroyed when the subscription got destroyed or object was destroyed
|
||||||
|
*/
|
||||||
|
struct weston_timeline_subscription_object {
|
||||||
|
void *object; /**< points to the object */
|
||||||
|
unsigned int id;
|
||||||
|
bool force_refresh;
|
||||||
|
struct wl_list subscription_link; /**< weston_timeline_subscription::objects */
|
||||||
|
struct wl_listener destroy_listener;
|
||||||
|
};
|
||||||
|
|
||||||
#define TYPEVERIFY(type, arg) ({ \
|
#define TYPEVERIFY(type, arg) ({ \
|
||||||
typeof(arg) tmp___ = (arg); \
|
typeof(arg) tmp___ = (arg); \
|
||||||
(void)((type)0 == tmp___); \
|
(void)((type)0 == tmp___); \
|
||||||
|
|||||||
Reference in New Issue
Block a user