profiler: use rt_events

Track the driver nodes and listen for rt events to collect stats.
This commit is contained in:
Wim Taymans 2023-07-17 19:13:19 +02:00
parent cfd3bcd6b2
commit 7ae59ff399
5 changed files with 107 additions and 65 deletions

View file

@ -71,6 +71,16 @@ static const struct spa_dict_item module_props[] = {
{ PW_KEY_MODULE_VERSION, PACKAGE_VERSION }, { PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
}; };
struct node {
struct spa_list link;
struct impl *impl;
struct pw_impl_node *node;
struct spa_hook node_rt_listener;
unsigned enabled:1;
};
struct impl { struct impl {
struct pw_context *context; struct pw_context *context;
struct pw_properties *properties; struct pw_properties *properties;
@ -84,6 +94,8 @@ struct impl {
struct pw_global *global; struct pw_global *global;
struct spa_hook global_listener; struct spa_hook global_listener;
struct spa_list node_list;
int64_t count; int64_t count;
uint32_t busy; uint32_t busy;
uint32_t empty; uint32_t empty;
@ -94,7 +106,6 @@ struct impl {
struct spa_ringbuffer buffer; struct spa_ringbuffer buffer;
uint8_t tmp[TMP_BUFFER]; uint8_t tmp[TMP_BUFFER];
uint8_t data[MAX_BUFFER]; uint8_t data[MAX_BUFFER];
uint8_t flush[MAX_BUFFER + sizeof(struct spa_pod_struct)]; uint8_t flush[MAX_BUFFER + sizeof(struct spa_pod_struct)];
}; };
@ -278,15 +289,88 @@ done:
impl->count++; impl->count++;
} }
static void node_complete(void *data)
{
struct node *n = data;
pw_log_info("complete");
context_do_profile(n->impl, n->node);
}
static struct pw_impl_node_rt_events node_rt_events = {
PW_VERSION_IMPL_NODE_RT_EVENTS,
.complete = node_complete,
};
static void enable_node_profiling(struct node *n, bool enabled)
{
if (enabled && !n->enabled) {
SPA_FLAG_SET(n->node->rt.target.activation->flags, PW_NODE_ACTIVATION_FLAG_PROFILER);
pw_impl_node_add_rt_listener(n->node, &n->node_rt_listener, &node_rt_events, n);
} else if (!enabled && n->enabled) {
SPA_FLAG_CLEAR(n->node->rt.target.activation->flags, PW_NODE_ACTIVATION_FLAG_PROFILER);
pw_impl_node_remove_rt_listener(n->node, &n->node_rt_listener);
}
n->enabled = enabled;
}
static void enable_profiling(struct impl *impl, bool enabled)
{
struct node *n;
spa_list_for_each(n, &impl->node_list, link)
enable_node_profiling(n, enabled);
}
static void context_driver_added(void *data, struct pw_impl_node *node)
{
struct impl *impl = data;
struct node *n;
n = calloc(1, sizeof(*n));
if (n == NULL)
return;
n->impl = impl;
n->node = node;
spa_list_append(&impl->node_list, &n->link);
if (impl->busy > 0)
enable_node_profiling(n, true);
}
static struct node *find_node(struct impl *impl, struct pw_impl_node *node)
{
struct node *n;
spa_list_for_each(n, &impl->node_list, link) {
if (n->node == node)
return n;
}
return NULL;
}
static void context_driver_removed(void *data, struct pw_impl_node *node)
{
struct impl *impl = data;
struct node *n;
n = find_node(impl, node);
if (n == NULL)
return;
enable_node_profiling(n, false);
spa_list_remove(&n->link);
free(n);
}
static const struct pw_context_events context_events = { static const struct pw_context_events context_events = {
PW_VERSION_CONTEXT_EVENTS, PW_VERSION_CONTEXT_EVENTS,
.profiler = context_do_profile, .driver_added = context_driver_added,
.driver_removed = context_driver_removed,
}; };
static void stop_listener(struct impl *impl) static void stop_listener(struct impl *impl)
{ {
if (impl->listening) { if (impl->listening) {
pw_context_stop_profiler(impl->context); enable_profiling(impl, false);
impl->listening = false; impl->listening = false;
} }
} }
@ -329,7 +413,7 @@ global_bind(void *object, struct pw_impl_client *client, uint32_t permissions,
if (++impl->busy == 1) { if (++impl->busy == 1) {
pw_log_info("%p: starting profiler", impl); pw_log_info("%p: starting profiler", impl);
pw_context_start_profiler(impl->context); enable_profiling(impl, true);
impl->listening = true; impl->listening = true;
} }
return 0; return 0;
@ -390,6 +474,7 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
if (impl == NULL) if (impl == NULL)
return -errno; return -errno;
spa_list_init(&impl->node_list);
pw_protocol_native_ext_profiler_init(context); pw_protocol_native_ext_profiler_init(context);
pw_log_debug("module %p: new %s", impl, args); pw_log_debug("module %p: new %s", impl, args);

View file

@ -479,53 +479,6 @@ void pw_context_add_listener(struct pw_context *context,
spa_hook_list_append(&context->listener_list, listener, events, data); spa_hook_list_append(&context->listener_list, listener, events, data);
} }
static void node_complete(void *data)
{
struct pw_impl_node *node = data;
pw_log_info("complete");
pw_context_emit_profiler(node->context, node);
}
static struct pw_impl_node_rt_events node_rt_events = {
PW_VERSION_IMPL_NODE_RT_EVENTS,
.complete = node_complete,
};
SPA_EXPORT
void pw_context_start_profiler(struct pw_context *context)
{
struct pw_impl_node *n;
pw_log_info("%d", context->profiling);
if (context->profiling++ > 0)
return;
spa_list_for_each(n, &context->driver_list, driver_link) {
if (SPA_FLAG_IS_SET(n->rt.target.activation->flags, PW_NODE_ACTIVATION_FLAG_PROFILER))
continue;
SPA_FLAG_SET(n->rt.target.activation->flags, PW_NODE_ACTIVATION_FLAG_PROFILER);
pw_impl_node_add_rt_listener(n, &n->profiler_listener, &node_rt_events, n);
}
}
SPA_EXPORT
void pw_context_stop_profiler(struct pw_context *context)
{
struct pw_impl_node *n;
pw_log_info("%d", context->profiling);
if (--context->profiling > 0)
return;
spa_list_for_each(n, &context->driver_list, driver_link) {
if (!SPA_FLAG_IS_SET(n->rt.target.activation->flags, PW_NODE_ACTIVATION_FLAG_PROFILER))
continue;
SPA_FLAG_CLEAR(n->rt.target.activation->flags, PW_NODE_ACTIVATION_FLAG_PROFILER);
pw_impl_node_remove_rt_listener(n, &n->profiler_listener);
}
}
SPA_EXPORT SPA_EXPORT
const struct spa_support *pw_context_get_support(struct pw_context *context, uint32_t *n_support) const struct spa_support *pw_context_get_support(struct pw_context *context, uint32_t *n_support)
{ {

View file

@ -64,8 +64,11 @@ struct pw_context_events {
void (*global_added) (void *data, struct pw_global *global); void (*global_added) (void *data, struct pw_global *global);
/** a global object was removed */ /** a global object was removed */
void (*global_removed) (void *data, struct pw_global *global); void (*global_removed) (void *data, struct pw_global *global);
/** a driver completed */
void (*profiler) (void *data, struct pw_impl_node *node); /** a driver was added */
void (*driver_added) (void *data, struct pw_impl_node *node);
/** a driver was removed */
void (*driver_removed) (void *data, struct pw_impl_node *node);
}; };
/** Make a new context object for a given main_loop. Ownership of the properties is taken */ /** Make a new context object for a given main_loop. Ownership of the properties is taken */
@ -171,11 +174,6 @@ int pw_context_set_object(struct pw_context *context, const char *type, void *va
/** get an object from the context */ /** get an object from the context */
void *pw_context_get_object(struct pw_context *context, const char *type); void *pw_context_get_object(struct pw_context *context, const char *type);
/** start the profiler, driver_completed events will be emited */
void pw_context_start_profiler(struct pw_context *context);
/** stop the profiler */
void pw_context_stop_profiler(struct pw_context *context);
/** /**
* \} * \}
*/ */

View file

@ -698,6 +698,13 @@ static inline void insert_driver(struct pw_context *context, struct pw_impl_node
break; break;
} }
spa_list_append(&n->driver_link, &node->driver_link); spa_list_append(&n->driver_link, &node->driver_link);
pw_context_emit_driver_added(context, node);
}
static inline void remove_driver(struct pw_context *context, struct pw_impl_node *node)
{
spa_list_remove(&node->driver_link);
pw_context_emit_driver_removed(context, node);
} }
static void update_io(struct pw_impl_node *node) static void update_io(struct pw_impl_node *node)
@ -941,8 +948,9 @@ static void check_properties(struct pw_impl_node *node)
if (node->registered) { if (node->registered) {
if (driver) if (driver)
insert_driver(context, node); insert_driver(context, node);
else else {
spa_list_remove(&node->driver_link); remove_driver(context, node);
}
} }
if (driver && node->driver_node == node) if (driver && node->driver_node == node)
node->driving = true; node->driving = true;
@ -2044,7 +2052,7 @@ void pw_impl_node_destroy(struct pw_impl_node *node)
if (node->registered) { if (node->registered) {
spa_list_remove(&node->link); spa_list_remove(&node->link);
if (node->driver) if (node->driver)
spa_list_remove(&node->driver_link); remove_driver(context, node);
} }
if (node->node) { if (node->node) {

View file

@ -371,7 +371,8 @@ int pw_loop_check(struct pw_loop *loop);
#define pw_context_emit_check_access(c,cl) pw_context_emit(c, check_access, 0, cl) #define pw_context_emit_check_access(c,cl) pw_context_emit(c, check_access, 0, cl)
#define pw_context_emit_global_added(c,g) pw_context_emit(c, global_added, 0, g) #define pw_context_emit_global_added(c,g) pw_context_emit(c, global_added, 0, g)
#define pw_context_emit_global_removed(c,g) pw_context_emit(c, global_removed, 0, g) #define pw_context_emit_global_removed(c,g) pw_context_emit(c, global_removed, 0, g)
#define pw_context_emit_profiler(c,n) pw_context_emit(c, profiler, 1, n) #define pw_context_emit_driver_added(c,n) pw_context_emit(c, driver_added, 1, n)
#define pw_context_emit_driver_removed(c,n) pw_context_emit(c, driver_removed, 1, n)
struct pw_context { struct pw_context {
struct pw_impl_core *core; /**< core object */ struct pw_impl_core *core; /**< core object */
@ -427,8 +428,6 @@ struct pw_context {
long sc_pagesize; long sc_pagesize;
unsigned int freewheeling:1; unsigned int freewheeling:1;
int profiling;
void *user_data; /**< extra user data */ void *user_data; /**< extra user data */
}; };
@ -730,7 +729,6 @@ struct pw_impl_node {
uint64_t target_quantum; uint64_t target_quantum;
uint64_t driver_start; uint64_t driver_start;
struct spa_hook profiler_listener;
void *user_data; /**< extra user data */ void *user_data; /**< extra user data */
}; };